Skip to main content

Using Layouts

Having wrapped our app with the necessary styling components, we're now ready to add our layout into the application. Refine provides default layouts for its supported UI libraries through <ThemedLayoutV2 /> components, delivering a two-column layout with a sidebar and a main content area.

<ThemedLayoutV2 /> components includes an header with user information (if an authProvider is provided), a sidebar with navigation links based on your resource definitions, a logout button (if an authProvider is provided), and a main content area where your content will be rendered.

TIP

Notice that we've removed the <Header /> component from our app since the layout already includes the same features.

Adding a Custom Title

Layout components are a composition of smaller components and they can be customized by providing respective props. The <ThemedLayoutV2 /> component consists of the following components:

  • <ThemedHeaderV2 /> for the header and can be customized via Header prop.
  • <ThemedSiderV2 /> for the sidebar and can be customized via Sider prop.
  • <ThemedTitleV2 /> for the logo and the title of the app and can be customized via Title prop.
  • There are also Footer and OffLayoutArea props for the footer and off-layout area respectively but they don't have default components for the layout.

Let's change the title of our app with using the Title prop of the <ThemedLayoutV2 /> component and the <ThemedTitleV2 /> component.

Update your src/App.tsx file by adding the following lines:

src/App.tsx
import { Refine, Authenticated } from "@refinedev/core";
import routerProvider, { NavigateToResource } from "@refinedev/react-router-v6";
import { ThemedLayoutV2, ThemedTitleV2 } from "@refinedev/antd";

import { BrowserRouter, Routes, Route, Outlet } from "react-router-dom";

import { ConfigProvider, App as AntdApp } from "antd";

import { dataProvider } from "./providers/data-provider";
import { authProvider } from "./providers/auth-provider";

import { ShowProduct } from "./pages/products/show";
import { EditProduct } from "./pages/products/edit";
import { ListProducts } from "./pages/products/list";
import { CreateProduct } from "./pages/products/create";

import { Login } from "./pages/login";

import "antd/dist/reset.css";

export default function App(): JSX.Element {
return (
<BrowserRouter>
<ConfigProvider>
<AntdApp>
<Refine
dataProvider={dataProvider}
authProvider={authProvider}
routerProvider={routerProvider}
resources={[
{
name: "protected-products",
list: "/products",
show: "/products/:id",
edit: "/products/:id/edit",
create: "/products/create",
meta: { label: "Products" },
},
]}
>
<Routes>
<Route
element={
<Authenticated
key="authenticated-routes"
redirectOnFail="/login"
>
<ThemedLayoutV2
Title={(props) => (
<ThemedTitleV2 {...props} text="Awesome Project" />
)}
>
<Outlet />
</ThemedLayoutV2>
</Authenticated>
}
>
{/* ... */}
</Route>
{/* ... */}
</Routes>
</Refine>
</AntdApp>
</ConfigProvider>
</BrowserRouter>
);
}

Our app is now wrapped with a customized layout that includes a sidebar and a main content area. We've updated our app's name with a single line of code, rest of the props works in the same manner.

TIP

Notice that our protected-products resource is listed in the sidebar with "Products" label. This is because we've provided a custom label for our resource in the meta.label field of our resource definition.

In the next step, we'll be refactoring our action components to use forms and tables from Ant Design.

Was this helpful?
import { Refine, Authenticated } from "@refinedev/core";
import routerProvider, { NavigateToResource } from "@refinedev/react-router-v6";
import { ThemedLayoutV2 } from "@refinedev/antd";

import { BrowserRouter, Routes, Route, Outlet } from "react-router-dom";

// We'll wrap our app with Ant Design's ConfigProvider to set the theme and App component to use the theme properly.
import { ConfigProvider, App as AntdApp } from "antd";

import { dataProvider } from "./providers/data-provider";
import { authProvider } from "./providers/auth-provider";

import { ShowProduct } from "./pages/products/show";
import { EditProduct } from "./pages/products/edit";
import { ListProducts } from "./pages/products/list";
import { CreateProduct } from "./pages/products/create";

import { Login } from "./pages/login";

// We're importing a reset.css file to reset the default styles of the browser.
import "antd/dist/reset.css";

export default function App(): JSX.Element {
  return (
    <BrowserRouter>
      <ConfigProvider>
        <AntdApp>
          <Refine
            dataProvider={dataProvider}
            authProvider={authProvider}
            routerProvider={routerProvider}
            resources={[
              {
                name: "protected-products",
                list: "/products",
                show: "/products/:id",
                edit: "/products/:id/edit",
                create: "/products/create",
                meta: { label: "Products" },
              },
            ]}
          >
            <Routes>
              <Route
                element={
                  <Authenticated
                    key="authenticated-routes"
                    redirectOnFail="/login"
                  >
                    <ThemedLayoutV2>
                      <Outlet />
                    </ThemedLayoutV2>
                  </Authenticated>
                }
              >
                <Route
                  index
                  element={<NavigateToResource resource="protected-products" />}
                />
                <Route path="/products">
                  <Route index element={<ListProducts />} />
                  <Route path=":id" element={<ShowProduct />} />
                  <Route path=":id/edit" element={<EditProduct />} />
                  <Route path="create" element={<CreateProduct />} />
                </Route>
              </Route>
              <Route
                element={
                  <Authenticated key="auth-pages" fallback={<Outlet />}>
                    <NavigateToResource resource="protected-products" />
                  </Authenticated>
                }
              >
                <Route path="/login" element={<Login />} />
              </Route>
            </Routes>
          </Refine>
        </AntdApp>
      </ConfigProvider>
    </BrowserRouter>
  );
}
installing dependencies
installing dependencies