Skip to main content
Refine is UI-agnostic and works seamlessly with any UI framework. It provides first-class integrations with popular UI libraries, offering pre-built components and hooks that work out of the box.

Supported UI Frameworks

Refine officially supports these UI frameworks:
  • Ant Design - Enterprise-grade UI components
  • Material UI (MUI) - Google’s Material Design components
  • Mantine - Modern React components library
  • Chakra UI - Simple and composable components
  • Headless - Build your own UI from scratch

Choosing a UI Framework

Ant Design

Best for enterprise applications with complex data tables and forms. Pros:
  • Rich set of components
  • Excellent table and form components
  • Strong TypeScript support
  • Large community
Installation:
npm install @refinedev/antd antd

Material UI

Best for applications following Material Design guidelines. Pros:
  • Google’s design system
  • Highly customizable
  • Great accessibility
  • Excellent documentation
Installation:
npm install @refinedev/mui @mui/material @mui/x-data-grid @emotion/react @emotion/styled

Mantine

Best for modern applications with a focus on developer experience. Pros:
  • Modern design
  • Great DX with hooks
  • Built-in dark mode
  • Lightweight
Installation:
npm install @refinedev/mantine @mantine/core @mantine/hooks @mantine/notifications

Chakra UI

Best for applications prioritizing accessibility and customization. Pros:
  • Accessibility-first
  • Style props API
  • Dark mode support
  • Component composition
Installation:
npm install @refinedev/chakra-ui @chakra-ui/react @emotion/react @emotion/styled framer-motion

Getting Started

1
Install the UI Package
2
Choose your preferred UI framework and install it:
3
npm install @refinedev/antd antd
4
Set Up the Provider
5
Wrap your app with the UI provider and configure Refine:
6
Ant Design
import { Refine } from "@refinedev/core";
import { ThemedLayoutV2, RefineThemes } from "@refinedev/antd";
import { ConfigProvider, App as AntdApp } from "antd";
import "@refinedev/antd/dist/reset.css";

const App = () => (
  <ConfigProvider theme={RefineThemes.Blue}>
    <AntdApp>
      <Refine
        // ... other props
      >
        <ThemedLayoutV2>
          {/* Your routes */}
        </ThemedLayoutV2>
      </Refine>
    </AntdApp>
  </ConfigProvider>
);
Material UI
import { Refine } from "@refinedev/core";
import { ThemedLayoutV2, RefineThemes } from "@refinedev/mui";
import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";

const App = () => (
  <ThemeProvider theme={RefineThemes.Blue}>
    <CssBaseline />
    <Refine
      // ... other props
    >
      <ThemedLayoutV2>
        {/* Your routes */}
      </ThemedLayoutV2>
    </Refine>
  </ThemeProvider>
);
Mantine
import { Refine } from "@refinedev/core";
import { ThemedLayoutV2, RefineThemes } from "@refinedev/mantine";
import { MantineProvider } from "@mantine/core";
import { NotificationsProvider } from "@mantine/notifications";

const App = () => (
  <MantineProvider theme={RefineThemes.Blue}>
    <NotificationsProvider>
      <Refine
        // ... other props
      >
        <ThemedLayoutV2>
          {/* Your routes */}
        </ThemedLayoutV2>
      </Refine>
    </NotificationsProvider>
  </MantineProvider>
);
Chakra UI
import { Refine } from "@refinedev/core";
import { ThemedLayoutV2, RefineThemes } from "@refinedev/chakra-ui";
import { ChakraProvider } from "@chakra-ui/react";

const App = () => (
  <ChakraProvider theme={RefineThemes.Blue}>
    <Refine
      // ... other props
    >
      <ThemedLayoutV2>
        {/* Your routes */}
      </ThemedLayoutV2>
    </Refine>
  </ChakraProvider>
);
7
Use Pre-built Components
8
Start using components and hooks:
9
import { List, EditButton, ShowButton } from "@refinedev/antd";
import { Table } from "antd";
import { useTable } from "@refinedev/antd";

export const PostList = () => {
  const { tableProps } = useTable();

  return (
    <List>
      <Table {...tableProps} rowKey="id">
        <Table.Column dataIndex="id" title="ID" />
        <Table.Column dataIndex="title" title="Title" />
        <Table.Column
          title="Actions"
          render={(_, record) => (
            <>
              <EditButton size="small" recordItemId={record.id} />
              <ShowButton size="small" recordItemId={record.id} />
            </>
          )}
        />
      </Table>
    </List>
  );
};

Pre-built Components

All UI packages provide these essential components:

Layout Components

import { ThemedLayoutV2, ThemedSiderV2, ThemedHeaderV2, ThemedTitleV2 } from "@refinedev/antd";

<ThemedLayoutV2
  Header={() => <ThemedHeaderV2 />}
  Sider={() => <ThemedSiderV2 />}
  Title={({ collapsed }) => <ThemedTitleV2 collapsed={collapsed} text="My App" />}
>
  {/* Your content */}
</ThemedLayoutV2>

Basic View Components

Wrapper components for CRUD pages:
import { List } from "@refinedev/antd";
import { Table } from "antd";

export const PostList = () => {
  const { tableProps } = useTable();

  return (
    <List>
      <Table {...tableProps}>
        {/* columns */}
      </Table>
    </List>
  );
};

Action Buttons

Pre-configured buttons for common actions:
import {
  CreateButton,
  EditButton,
  ShowButton,
  DeleteButton,
  RefreshButton,
  ListButton,
  SaveButton,
  CloneButton,
} from "@refinedev/antd";

// In a list
<CreateButton />
<RefreshButton />

// In table actions
<EditButton recordItemId={record.id} />
<ShowButton recordItemId={record.id} />
<DeleteButton recordItemId={record.id} />
<CloneButton recordItemId={record.id} />

// In forms
<SaveButton />
<ListButton />

Field Components

Display data with formatted components:
import {
  TextField,
  NumberField,
  DateField,
  EmailField,
  UrlField,
  BooleanField,
  TagField,
  MarkdownField,
  ImageField,
} from "@refinedev/antd";

<TextField value={record.title} />
<NumberField value={record.price} options={{ style: "currency", currency: "USD" }} />
<DateField value={record.createdAt} format="LLL" />
<EmailField value={record.email} />
<UrlField value={record.website} />
<BooleanField value={record.isPublished} />
<TagField value={record.status} />
<MarkdownField value={record.content} />
<ImageField value={record.image} width={200} />

UI-Specific Hooks

Form Hooks

import { useForm } from "@refinedev/antd";

const { formProps, saveButtonProps, queryResult } = useForm({
  action: "create", // or "edit"
  resource: "posts",
  redirect: "list",
});

<Form {...formProps}>
  <Form.Item name="title">
    <Input />
  </Form.Item>
</Form>

Table Hooks

import { useTable } from "@refinedev/antd";
import { Table } from "antd";

const { tableProps, searchFormProps, filters } = useTable({
  resource: "posts",
  filters: {
    initial: [
      { field: "status", operator: "eq", value: "published" },
    ],
  },
  sorters: {
    initial: [
      { field: "createdAt", order: "desc" },
    ],
  },
});

<Table {...tableProps} rowKey="id">
  <Table.Column dataIndex="title" title="Title" sorter />
  <Table.Column dataIndex="status" title="Status" />
</Table>

Select/Autocomplete Hooks

For handling relationships and foreign keys:
import { useSelect } from "@refinedev/antd";
import { Select } from "antd";

const { selectProps } = useSelect({
  resource: "categories",
  optionLabel: "title",
  optionValue: "id",
});

<Select {...selectProps} />

Theming and Customization

Using Built-in Themes

Each UI package comes with pre-configured themes:
import { RefineThemes } from "@refinedev/antd";
import { ConfigProvider } from "antd";

<ConfigProvider theme={RefineThemes.Blue}>
  {/* Blue, Purple, Magenta, Red, Orange, Yellow, Green */}
</ConfigProvider>

Creating Custom Themes

import { ConfigProvider } from "antd";

const customTheme = {
  token: {
    colorPrimary: "#1890ff",
    borderRadius: 6,
  },
};

<ConfigProvider theme={customTheme}>
  <App />
</ConfigProvider>

Dark Mode

All UI frameworks support dark mode:
import { ConfigProvider, theme } from "antd";

const [isDark, setIsDark] = useState(false);

<ConfigProvider
  theme={{
    algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm,
  }}
>
  <App />
</ConfigProvider>

Building Headless

If you prefer to build your own UI:
import { Refine } from "@refinedev/core";
import { useTable, useForm, useShow } from "@refinedev/core";

const PostList = () => {
  const {
    tableQuery: { data, isLoading },
    current,
    setCurrent,
    pageSize,
    setPageSize,
    filters,
    setFilters,
  } = useTable({
    resource: "posts",
  });

  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      <h1>Posts</h1>
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>Title</th>
            <th>Status</th>
          </tr>
        </thead>
        <tbody>
          {data?.data.map((post) => (
            <tr key={post.id}>
              <td>{post.id}</td>
              <td>{post.title}</td>
              <td>{post.status}</td>
            </tr>
          ))}
        </tbody>
      </table>
      
      {/* Custom pagination */}
      <div>
        <button onClick={() => setCurrent(current - 1)}>Previous</button>
        <span>Page {current}</span>
        <button onClick={() => setCurrent(current + 1)}>Next</button>
      </div>
    </div>
  );
};

Mixing UI Frameworks

You can use components from different frameworks:
import { ThemedLayoutV2 } from "@refinedev/antd";
import { Button } from "@mui/material";

// Use Ant Design layout with Material UI button
<ThemedLayoutV2>
  <Button variant="contained">Material UI Button</Button>
</ThemedLayoutV2>

Best Practices

  1. Choose one primary UI framework - Stick to one framework for consistency
  2. Use the framework’s hooks - UI-specific hooks provide better integration
  3. Leverage pre-built components - Save development time with ready-made components
  4. Customize themes - Match your brand with custom themes
  5. Follow accessibility guidelines - All frameworks support WCAG standards
  6. Use TypeScript - Get better autocomplete and type safety

Migration Between Frameworks

Switching UI frameworks is straightforward since Refine’s core is UI-agnostic:
  1. Install the new UI package
  2. Update imports in your components
  3. Replace UI-specific hooks with the new framework’s equivalents
  4. Update component props to match the new framework
Core logic (data fetching, auth, routing) remains unchanged!

Next Steps

Build docs developers (and LLMs) love