Skip to main content
Refine provides comprehensive support for Material-UI (MUI), Google’s Material Design implementation for React. The @refinedev/mui package offers pre-built components that integrate seamlessly with Refine’s core functionality.

Installation

npm install @refinedev/mui @mui/material @mui/x-data-grid @mui/lab @mui/icons-material @emotion/react @emotion/styled dayjs

Setup

Basic Setup

Wrap your application with MUI’s theme provider:
App.tsx
import { Refine } from "@refinedev/core";
import {
  ThemedLayout,
  RefineThemes,
  useNotificationProvider,
  RefineSnackbarProvider,
} from "@refinedev/mui";
import { CssBaseline, GlobalStyles, ThemeProvider } from "@mui/material";
import dataProvider from "@refinedev/simple-rest";

function App() {
  return (
    <ThemeProvider theme={RefineThemes.Blue}>
      <CssBaseline />
      <GlobalStyles styles={{ html: { WebkitFontSmoothing: "auto" } }} />
      <RefineSnackbarProvider>
        <Refine
          dataProvider={dataProvider("https://api.example.com")}
          notificationProvider={useNotificationProvider}
          resources={[
            {
              name: "products",
              list: "/products",
              create: "/products/create",
              edit: "/products/edit/:id",
              show: "/products/show/:id",
            },
          ]}
        >
          <ThemedLayout>
            {/* Your pages here */}
          </ThemedLayout>
        </Refine>
      </RefineSnackbarProvider>
    </ThemeProvider>
  );
}

export default App;

Available Themes

Refine provides pre-configured Material-UI themes:
import { RefineThemes } from "@refinedev/mui";

// Available themes:
RefineThemes.Blue
RefineThemes.Purple
RefineThemes.Magenta
RefineThemes.Red
RefineThemes.Orange
RefineThemes.Yellow
RefineThemes.BlueDark  // Dark mode variants
RefineThemes.PurpleDark

Custom Theme

Customize the theme using Material-UI’s createTheme:
import { createTheme, ThemeProvider } from "@mui/material";

const theme = createTheme({
  palette: {
    mode: "dark",
    primary: {
      main: "#1976d2",
    },
    secondary: {
      main: "#dc004e",
    },
  },
  typography: {
    fontFamily: "Inter, sans-serif",
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      {/* Your app */}
    </ThemeProvider>
  );
}

Layout Components

ThemedLayout

The main layout component with sidebar, header, and content:
import { ThemedLayout } from "@refinedev/mui";

function App() {
  return (
    <Refine
      // ... other props
    >
      <ThemedLayout>
        {/* Your routes */}
      </ThemedLayout>
    </Refine>
  );
}

Custom Layout Components

import {
  ThemedLayout,
  ThemedSider,
  ThemedHeader,
  ThemedTitle,
} from "@refinedev/mui";

function App() {
  return (
    <ThemedLayout
      Sider={() => <ThemedSider />}
      Header={() => <ThemedHeader sticky />}
      Title={({ collapsed }) => (
        <ThemedTitle collapsed={collapsed} text="My Admin" />
      )}
    >
      {/* Your routes */}
    </ThemedLayout>
  );
}

CRUD Components

List

Display list with Material-UI DataGrid:
pages/products/list.tsx
import { List, useDataGrid, EditButton, ShowButton } from "@refinedev/mui";
import { DataGrid, GridColDef } from "@mui/x-data-grid";

export const ProductList = () => {
  const { dataGridProps } = useDataGrid();

  const columns: GridColDef[] = [
    { field: "id", headerName: "ID", width: 70 },
    { field: "name", headerName: "Name", flex: 1 },
    {
      field: "price",
      headerName: "Price",
      type: "number",
      width: 130,
    },
    {
      field: "actions",
      headerName: "Actions",
      renderCell: ({ row }) => (
        <>
          <EditButton hideText recordItemId={row.id} />
          <ShowButton hideText recordItemId={row.id} />
        </>
      ),
      width: 150,
    },
  ];

  return (
    <List>
      <DataGrid {...dataGridProps} columns={columns} autoHeight />
    </List>
  );
};

Create

Create form with Material-UI components:
pages/products/create.tsx
import { Create, useForm } from "@refinedev/mui";
import { Box, TextField } from "@mui/material";
import { useForm as useHookForm } from "@refinedev/react-hook-form";

export const ProductCreate = () => {
  const {
    saveButtonProps,
    refineCore: { formLoading },
    register,
    formState: { errors },
  } = useForm();

  return (
    <Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
      <Box
        component="form"
        sx={{ display: "flex", flexDirection: "column", gap: 2 }}
        autoComplete="off"
      >
        <TextField
          {...register("name", {
            required: "Name is required",
          })}
          error={!!errors.name}
          helperText={errors.name?.message}
          label="Name"
          name="name"
        />
        <TextField
          {...register("price", {
            required: "Price is required",
          })}
          error={!!errors.price}
          helperText={errors.price?.message}
          label="Price"
          name="price"
          type="number"
        />
        <TextField
          {...register("description")}
          label="Description"
          name="description"
          multiline
          rows={4}
        />
      </Box>
    </Create>
  );
};

Edit

Edit form with automatic data fetching:
pages/products/edit.tsx
import { Edit, useForm } from "@refinedev/mui";
import { Box, TextField } from "@mui/material";

export const ProductEdit = () => {
  const {
    saveButtonProps,
    refineCore: { queryResult, formLoading },
    register,
    formState: { errors },
  } = useForm();

  return (
    <Edit isLoading={formLoading} saveButtonProps={saveButtonProps}>
      <Box
        component="form"
        sx={{ display: "flex", flexDirection: "column", gap: 2 }}
      >
        <TextField
          {...register("id")}
          disabled
          label="ID"
          name="id"
        />
        <TextField
          {...register("name", {
            required: "Name is required",
          })}
          error={!!errors.name}
          helperText={errors.name?.message}
          label="Name"
          name="name"
        />
        <TextField
          {...register("price", {
            required: "Price is required",
          })}
          error={!!errors.price}
          helperText={errors.price?.message}
          label="Price"
          name="price"
          type="number"
        />
      </Box>
    </Edit>
  );
};

Show

Display single record:
pages/products/show.tsx
import {
  Show,
  TextField,
  NumberField,
  DateField,
} from "@refinedev/mui";
import { useShow } from "@refinedev/core";
import { Typography, Stack } from "@mui/material";

export const ProductShow = () => {
  const { queryResult } = useShow();
  const { data, isLoading } = queryResult;
  const record = data?.data;

  return (
    <Show isLoading={isLoading}>
      <Stack gap={1}>
        <Typography variant="body1" fontWeight="bold">
          ID
        </Typography>
        <TextField value={record?.id} />

        <Typography variant="body1" fontWeight="bold">
          Name
        </Typography>
        <TextField value={record?.name} />

        <Typography variant="body1" fontWeight="bold">
          Price
        </Typography>
        <NumberField
          value={record?.price}
          options={{
            style: "currency",
            currency: "USD",
          }}
        />

        <Typography variant="body1" fontWeight="bold">
          Created At
        </Typography>
        <DateField value={record?.createdAt} />
      </Stack>
    </Show>
  );
};

Field Components

Material-UI field components for displaying data:
import {
  TextField,
  NumberField,
  DateField,
  EmailField,
  UrlField,
  BooleanField,
  TagField,
  MarkdownField,
} from "@refinedev/mui";
import { Stack } from "@mui/material";

function FieldExamples() {
  return (
    <Stack spacing={2}>
      <TextField value="Simple text" />
      
      <NumberField
        value={1234.56}
        options={{ style: "currency", currency: "USD" }}
      />
      
      <DateField value="2024-01-15" format="LL" />
      
      <EmailField value="[email protected]" />
      
      <UrlField value="https://example.com" />
      
      <BooleanField value={true} />
      
      <TagField value="Active" />
      
      <MarkdownField value="# Hello\n\nThis is **markdown**" />
    </Stack>
  );
}

Button Components

Material-UI styled action buttons:
import {
  CreateButton,
  EditButton,
  ShowButton,
  DeleteButton,
  ListButton,
  RefreshButton,
  SaveButton,
  CloneButton,
  ExportButton,
  ImportButton,
} from "@refinedev/mui";
import { Stack } from "@mui/material";

function ButtonExamples() {
  return (
    <Stack direction="row" spacing={1}>
      <CreateButton resource="products" />
      <EditButton resource="products" recordItemId="1" />
      <ShowButton resource="products" recordItemId="1" />
      <DeleteButton resource="products" recordItemId="1" />
      <ListButton resource="products" />
      <RefreshButton resource="products" />
      <SaveButton />
      <CloneButton resource="products" recordItemId="1" />
      <ExportButton />
      <ImportButton />
    </Stack>
  );
}

Advanced Features

Data Grid with Filters

import { List, useDataGrid } from "@refinedev/mui";
import { DataGrid, GridColDef } from "@mui/x-data-grid";

export const ProductList = () => {
  const { dataGridProps } = useDataGrid({
    initialSorter: [
      {
        field: "id",
        order: "desc",
      },
    ],
    initialFilter: [
      {
        field: "status",
        operator: "eq",
        value: "active",
      },
    ],
  });

  const columns: GridColDef[] = [
    { field: "id", headerName: "ID", width: 70 },
    {
      field: "name",
      headerName: "Name",
      flex: 1,
      filterable: true,
    },
    {
      field: "status",
      headerName: "Status",
      width: 130,
      type: "singleSelect",
      valueOptions: ["active", "inactive"],
    },
    {
      field: "price",
      headerName: "Price",
      type: "number",
      width: 130,
    },
  ];

  return (
    <List>
      <DataGrid
        {...dataGridProps}
        columns={columns}
        autoHeight
        filterMode="server"
        sortingMode="server"
      />
    </List>
  );
};
import { useModalForm, CreateButton, Create } from "@refinedev/mui";
import { Dialog, DialogContent, TextField, Box } from "@mui/material";

export const ProductList = () => {
  const {
    modal: { visible, close },
    show,
    register,
    formState: { errors },
    saveButtonProps,
  } = useModalForm({
    refineCoreProps: { action: "create" },
  });

  return (
    <>
      <CreateButton onClick={() => show()} />
      
      <Dialog open={visible} onClose={close}>
        <DialogContent>
          <Create saveButtonProps={saveButtonProps}>
            <Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
              <TextField
                {...register("name", { required: "Name is required" })}
                error={!!errors.name}
                helperText={errors.name?.message}
                label="Name"
              />
            </Box>
          </Create>
        </DialogContent>
      </Dialog>
    </>
  );
};

Auto-Save Indicator

import { AutoSaveIndicator, useForm } from "@refinedev/mui";
import { Box, TextField } from "@mui/material";

export const ProductEdit = () => {
  const {
    register,
    refineCore: { autoSaveProps },
  } = useForm({
    refineCoreProps: {
      autoSave: {
        enabled: true,
        debounce: 2000,
      },
    },
  });

  return (
    <>
      <AutoSaveIndicator {...autoSaveProps} />
      <Box component="form" sx={{ display: "flex", flexDirection: "column" }}>
        <TextField {...register("name")} label="Name" />
      </Box>
    </>
  );
};

Responsive Layout

import { ThemedLayout } from "@refinedev/mui";
import { useMediaQuery, useTheme } from "@mui/material";

function App() {
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down("sm"));

  return (
    <ThemedLayout
      Sider={() => (
        <ThemedSider
          render={({ items, logout, collapsed }) => (
            // Custom sider rendering
            <>{items}</>
          )}
        />
      )}
    >
      {/* Your routes */}
    </ThemedLayout>
  );
}

Next Steps

Material-UI Docs

Official Material-UI documentation

Examples

See complete MUI examples

DataGrid

Learn about MUI DataGrid

Theming

Customize your theme

Build docs developers (and LLMs) love