Skip to main content

Overview

The SidebarLayout component is the default layout for Tailor Platform applications. It provides:
  • Collapsible sidebar navigation
  • Responsive mobile menu
  • Dynamic breadcrumb navigation
  • Theme toggle button
  • Content outlet for page rendering
This component should be used as a direct child of AppShell.

Props

children
(props: { Outlet: () => React.ReactNode }) => React.ReactNode
Custom content renderer that receives an Outlet component for rendering page content.
<SidebarLayout>
  {({ Outlet }) => (
    <>
      <CustomHeader />
      <Outlet />
      <CustomFooter />
    </>
  )}
</SidebarLayout>
sidebar
React.ReactNode
Custom sidebar component. Defaults to DefaultSidebar.
<SidebarLayout sidebar={<MyCustomSidebar />} />

Features

Responsive Behavior

  • Desktop: Sidebar is visible and collapsible
  • Mobile: Sidebar slides in as an overlay (offcanvas)
  • Icon Mode: Sidebar collapses to icon-only mode on narrow screens

Built-in Header

The header includes:
  • Sidebar toggle button (hidden when sidebar is open on desktop)
  • Dynamic breadcrumb navigation
  • Theme toggle button (light/dark mode)

Content Area

The content area automatically renders:
  • Page components from your route configuration
  • Custom content via the children render prop

Usage Examples

Basic Usage

Simplest setup with all defaults:
import { AppShell, SidebarLayout } from "@tailor-platform/app-shell";

const App = () => (
  <AppShell title="My App">
    <SidebarLayout />
  </AppShell>
);

Custom Content Wrapper

Wrap page content with custom elements:
import { AppShell, SidebarLayout } from "@tailor-platform/app-shell";

const App = () => (
  <AppShell title="My App">
    <SidebarLayout>
      {({ Outlet }) => (
        <div className="custom-wrapper">
          <div className="page-header">
            <h1>Custom Header</h1>
          </div>
          <main className="page-content">
            <Outlet />
          </main>
          <footer className="page-footer">
            <p>© 2024 My Company</p>
          </footer>
        </div>
      )}
    </SidebarLayout>
  </AppShell>
);

Custom Sidebar

Replace the default sidebar with your own:
import { AppShell, SidebarLayout } from "@tailor-platform/app-shell";
import { MySidebar } from "./components/MySidebar";

const App = () => (
  <AppShell title="My App">
    <SidebarLayout sidebar={<MySidebar />} />
  </AppShell>
);

Using DefaultSidebar with Custom Header/Footer

import { 
  AppShell, 
  SidebarLayout, 
  DefaultSidebar 
} from "@tailor-platform/app-shell";

const SidebarHeader = () => (
  <div className="p-4">
    <img src="/logo.svg" alt="Logo" />
    <h1>My App</h1>
  </div>
);

const SidebarFooter = () => (
  <div className="p-4 border-t">
    <p className="text-sm">Version 1.0.0</p>
  </div>
);

const App = () => (
  <AppShell title="My App">
    <SidebarLayout 
      sidebar={
        <DefaultSidebar 
          header={<SidebarHeader />}
          footer={<SidebarFooter />}
        />
      }
    />
  </AppShell>
);

With Multiple Layout Sections

import { AppShell, SidebarLayout } from "@tailor-platform/app-shell";

const App = () => (
  <AppShell title="My App">
    <SidebarLayout>
      {({ Outlet }) => (
        <div className="layout-container">
          <aside className="left-panel">
            <QuickActions />
          </aside>
          <main className="main-content">
            <Outlet />
          </main>
          <aside className="right-panel">
            <Notifications />
          </aside>
        </div>
      )}
    </SidebarLayout>
  </AppShell>
);

DefaultSidebar

The DefaultSidebar component provides auto-generated navigation from your module configuration.

Props

header
React.ReactNode
Custom header content displayed at the top of the sidebar
Custom footer content displayed at the bottom of the sidebar
children
React.ReactNode
When provided, enables explicit sidebar composition using SidebarItem, SidebarGroup, and other components. Auto-generation is completely disabled when children is specified.

Auto-generation Mode

By default, DefaultSidebar automatically generates navigation items based on your module/resource definitions:
import { DefaultSidebar } from "@tailor-platform/app-shell";

// Automatically generates nav items from modules
<DefaultSidebar />

Composition Mode

Manually define sidebar structure using components:
import { 
  DefaultSidebar,
  SidebarItem,
  SidebarGroup,
  SidebarSeparator
} from "@tailor-platform/app-shell";

<DefaultSidebar>
  <SidebarItem to="/dashboard" />
  <SidebarGroup title="Products">
    <SidebarItem to="/products/all" />
    <SidebarItem to="/products/categories" />
  </SidebarGroup>
  <SidebarSeparator />
  <SidebarItem to="/settings" />
</DefaultSidebar>
When using composition mode, you can use these components:

SidebarItem

Renders a navigation link with automatic active state and icon/title from page metadata.
<SidebarItem to="/dashboard" />

SidebarGroup

Groups related navigation items together:
<SidebarGroup title="Products">
  <SidebarItem to="/products/all" />
  <SidebarItem to="/products/new" />
</SidebarGroup>

SidebarSeparator

Adds a visual divider between sidebar sections:
<SidebarItem to="/dashboard" />
<SidebarSeparator />
<SidebarItem to="/settings" />

Customization

Theme Toggle

The theme toggle button is built-in and uses the useTheme hook:
import { useTheme } from "@tailor-platform/app-shell";

const CustomThemeToggle = () => {
  const { theme, setTheme } = useTheme();
  
  return (
    <button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
      Toggle Theme
    </button>
  );
};
The breadcrumb is dynamically generated from your current route. Customize breadcrumb titles using meta.breadcrumbTitle in your module/resource definitions:
import { defineResource } from "@tailor-platform/app-shell";

defineResource({
  path: ":productId",
  meta: {
    title: "Product Details",
    breadcrumbTitle: (productId) => `Product ${productId}`
  },
  component: ProductDetails
});
Access sidebar state in custom components:
import { useSidebar } from "@tailor-platform/app-shell";

const CustomComponent = () => {
  const { open, isIconMode } = useSidebar();
  
  return (
    <div>
      Sidebar is {open ? 'open' : 'closed'}
      {isIconMode && <span>(Icon mode)</span>}
    </div>
  );
};

TypeScript

SidebarLayoutProps Type

type SidebarLayoutProps = {
  children?: (props: { Outlet: () => React.ReactNode }) => React.ReactNode;
  sidebar?: React.ReactNode;
};

DefaultSidebarProps Type

type DefaultSidebarProps = {
  header?: React.ReactNode;
  footer?: React.ReactNode;
  children?: React.ReactNode;
};

Styling

The sidebar uses Tailwind CSS with the astw: prefix. Customize the appearance by:
  1. Override CSS variables in your theme
  2. Apply custom classes to wrapper components
  3. Use the className prop on custom sidebar components
/* Custom sidebar styling */
:root {
  --sidebar-width: 280px;
  --sidebar-background: hsl(0 0% 98%);
}

.dark {
  --sidebar-background: hsl(0 0% 10%);
}

See Also

Build docs developers (and LLMs) love