# How to Create Custom Layouts by Extending BaseLayout in refine-shadcn

> Create custom layouts in refine-shadcn by extending BaseLayout. Inherit theme support and wrap your own headers, sidebars, or navigation drawers with ease.

- Repository: [Ferdi ÜNAL/refine-shadcn](https://github.com/ferdiunal/refine-shadcn)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Extend the `BaseLayout` component from `@ferdiunal/refine-shadcn` to create custom layouts that inherit global theme support, tooltips, and toast notifications while wrapping your own headers, sidebars, or navigation drawers.**

The `refine-shadcn` library provides a minimal, composable `BaseLayout` component located at [`packages/theme/src/layouts/base.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/base.tsx). This component deliberately handles only essential global providers—`ThemeProvider` from `next-themes`, `TooltipProvider`, and the `Toaster` notification system—freeing you to build any UI structure around the `{children}` content without reimplementing theme logic.

## BaseLayout Architecture and Type System

### The Core Component

In [`packages/theme/src/layouts/base.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/base.tsx), the `BaseLayout` component accepts props extending `ThemeProvider` options plus a `children` slot. It renders the global UI infrastructure that every page needs:

```tsx
export const BaseLayout = ({
    attribute,
    defaultTheme,
    enableSystem,
    // … other ThemeProvider props
    children,
}: Props) => (
    <ThemeProvider …>
        <TooltipProvider …>
            {children}
            <Toaster />
        </TooltipProvider>
    </ThemeProvider>
);

```

Because `BaseLayout` injects `{children}` directly inside the `TooltipProvider`, any custom layout you build will automatically support tooltips and theme switching while maintaining access to toast notifications via the `<Toaster />` element rendered as a sibling.

### LayoutProps Type Definitions

The contract for valid layout props is defined in [`packages/theme/src/types/layout.d.ts`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/types/layout.d.ts). The `LayoutProps` interface extends `ThemeProvider` properties and adds UI-specific fields such as `logo`, `navbar`, and `footer`, ensuring your custom layouts remain type-safe when accepting theme or branding configurations.

### DefaultLayout Reference Implementation

For a complete example of composition, examine [`packages/theme/src/layouts/default.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/default.tsx). This file demonstrates how to wrap `BaseLayout` with a responsive sidebar, header bar, and content area while forwarding all theme props unchanged.

## Creating a Minimal Header Layout

To create a simple layout that adds a fixed header above all page content, import `BaseLayout` and the `LayoutProps` type, then compose your UI inside the component’s children:

```tsx
// src/layouts/MyHeaderLayout.tsx
import { BaseLayout } from "@ferdiunal/refine-shadcn";
import { LayoutProps } from "@ferdiunal/refine-shadcn/dist/types/layout";
import { Header } from "@/components/header";

export const MyHeaderLayout = ({
  attribute,
  defaultTheme,
  enableSystem,
  children,
}: LayoutProps) => {
  return (
    <BaseLayout
      attribute={attribute}
      defaultTheme={defaultTheme}
      enableSystem={enableSystem}
    >
      <Header />
      {children}
    </BaseLayout>
  );
};

MyHeaderLayout.displayName = "MyHeaderLayout";

```

All theme-related props are passed through to `BaseLayout`, ensuring the `ThemeProvider` and `Toaster` remain active. The `<Header />` component renders above the page content while the toast container persists globally.

## Building a Full-Featured Drawer Layout

For complex layouts requiring responsive navigation, you can replicate the logic from `DefaultLayout` but substitute components. The following example replaces the sidebar with a mobile drawer while keeping the desktop header:

```tsx
// src/layouts/CustomDrawerLayout.tsx
import { BaseLayout } from "@ferdiunal/refine-shadcn";
import type { LayoutProps, LogoType } from "@ferdiunal/refine-shadcn";
import { useState, useMemo, cloneElement, isValidElement } from "react";
import { Drawer, DrawerTrigger, DrawerContent } from "@/components/drawer";
import { Link } from "@/components/link";
import { ModeToggle } from "@/components/mode-toggle";
import { useResource } from "@refinedev/core";
import { useMediaQuery } from "@react-hook/media-query";

export const CustomDrawerLayout = ({
  children,
  logo,
  navbar,
  footer,
  attribute,
  defaultTheme,
  enableSystem,
}: LayoutProps) => {
  const { resources } = useResource();
  const firstDashboard = resources?.[0];
  const isMobile = useMediaQuery("only screen and (max-width: 639px)");
  const [drawerOpen, setDrawerOpen] = useState(false);

  const Logo: LogoType | undefined = useMemo(() => {
    if (!logo) return null;
    const component = isMobile ? logo.collapsed : logo.default;
    return isValidElement(component)
      ? cloneElement(component, { className: "w-auto h-8" })
      : null;
  }, [logo, isMobile]);

  return (
    <BaseLayout
      attribute={attribute}
      defaultTheme={defaultTheme}
      enableSystem={enableSystem}
    >
      {isMobile && (
        <Drawer open={drawerOpen} onOpenChange={setDrawerOpen}>
          <DrawerTrigger asChild>
            <button className="p-2">☰</button>
          </DrawerTrigger>
          <DrawerContent>
            <nav className="flex flex-col space-y-2 p-4">
              <Link href={firstDashboard?.list?.toString() ?? "/"}>{Logo}</Link>
            </nav>
          </DrawerContent>
        </Drawer>
      )}

      {!isMobile && (
        <header className="flex h-14 items-center justify-between border-b p-4">
          <Link href={firstDashboard?.list?.toString() ?? "/"}>{Logo}</Link>
          <div className="flex items-center space-x-2">
            <ModeToggle />
            {navbar?.rightSide}
          </div>
        </header>
      )}

      <main className="px-6 py-4">{children}</main>

      {footer && <footer className="border-t p-4">{footer}</footer>}
    </BaseLayout>
  );
};

CustomDrawerLayout.displayName = "CustomDrawerLayout";

```

This implementation reuses the logo handling logic from `DefaultLayout` via the `useMemo` pattern, conditionally renders a `Drawer` for mobile viewports, and preserves all theme forwarding to `BaseLayout`.

## Using Your Custom Layout in an Application

Once defined, import your layout component into your application entry point and supply the theme configuration:

```tsx
// src/App.tsx
import { CustomDrawerLayout } from "@/layouts/CustomDrawerLayout";

function App() {
  return (
    <CustomDrawerLayout
      attribute="data-theme"
      defaultTheme="system"
      enableSystem
    >
      <MyDashboard />
    </CustomDrawerLayout>
  );
}

```

Passing `attribute`, `defaultTheme`, and `enableSystem` ensures the `next-themes` provider inside `BaseLayout` initializes correctly for your application.

## Summary

- **BaseLayout** in [`packages/theme/src/layouts/base.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/base.tsx) provides the essential `ThemeProvider`, `TooltipProvider`, and `Toaster` wrappers required by every refine-shadcn application.
- **LayoutProps** in [`packages/theme/src/types/layout.d.ts`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/types/layout.d.ts) defines the complete type contract, extending `ThemeProvider` props with UI-specific fields like `logo` and `navbar`.
- To create custom layouts, import `BaseLayout`, accept `LayoutProps` (or a subset), wrap your custom UI around `{children}`, and forward theme props unchanged.
- Reference [`packages/theme/src/layouts/default.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/default.tsx) for a production-ready example combining sidebars, headers, and responsive behavior.

## Frequently Asked Questions

### What props does BaseLayout accept?

`BaseLayout` accepts all props defined in `LayoutProps`, which extend `ThemeProvider` options from `next-themes` (such as `attribute`, `defaultTheme`, and `enableSystem`) plus React children. According to the source in [`packages/theme/src/layouts/base.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/base.tsx), any additional `ThemeProvider` props are destructured and passed directly to the provider.

### Can I use BaseLayout without a sidebar?

Yes. `BaseLayout` is intentionally minimal and does not enforce any navigation structure. You can wrap it around a simple header, a blank canvas, or a complex dashboard grid. The `DefaultLayout` in [`packages/theme/src/layouts/default.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/default.tsx) provides one example with a sidebar, but you are not required to include one.

### How do I access theme settings inside my custom layout?

Because `BaseLayout` renders `ThemeProvider` from `next-themes`, you can use the `useTheme` hook from that library anywhere inside your layout’s component tree. Your custom layout component receives theme props (like `attribute` and `defaultTheme`) via `LayoutProps`, which you must forward to `BaseLayout` to initialize the provider.

### Where is the DefaultLayout defined?

The reference implementation is located at [`packages/theme/src/layouts/default.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/layouts/default.tsx) in the `ferdiunal/refine-shadcn` repository. This file demonstrates how to compose `BaseLayout` with a responsive sidebar, header, and content area while handling logo states and resource navigation.