Layout

Layout

Complete layout system with sidebar navigation, main content area, and page sections for building consistent application interfaces

Installation

npm install @marmoui/ui
yarn add @marmoui/ui
pnpm add @marmoui/ui
bun add @marmoui/ui

Usage

Import the layout components from the package:

import { 
  SidebarProvider, 
  SideNavigation,
  SidebarPanel,
  SidebarItem,
  SidebarSubItem 
} from '@marmoui/ui';

Examples

Complete Application Layout

Full Application Shell

Complete layout with sidebar and main content

const mainNavItems = [
{
  id: 'dashboard',
  label: 'Dashboard',
  iconOutlined: MdOutlineDashboard,
  iconFilled: MdDashboard,
  path: '/dashboard',
  secondaryItems: [
    { id: 'overview', label: 'Overview', path: '/dashboard/overview' },
    { id: 'analytics', label: 'Analytics', path: '/dashboard/analytics' },
  ],
},
{
  id: 'campaigns',
  label: 'Campaigns',
  iconOutlined: MdOutlineCampaign,
  iconFilled: MdCampaign,
  path: '/campaigns',
  secondaryItems: [
    { id: 'active', label: 'Active', path: '/campaigns/active' },
    { id: 'drafts', label: 'Drafts', path: '/campaigns/drafts' },
    { id: 'archived', label: 'Archived', path: '/campaigns/archived' },
  ],
},
{
  id: 'contacts',
  label: 'Contacts',
  iconOutlined: MdPeopleOutline,
  iconFilled: MdPeople,
  path: '/contacts',
  secondaryItems: [
    { id: 'all', label: 'All Contacts', path: '/contacts/all' },
    { id: 'segments', label: 'Segments', path: '/contacts/segments' },
  ],
},
];

function AppLayout({ children }) {
return (
  <SidebarProvider mainNavItems={mainNavItems}>
    <div className="flex h-screen">
      <SideNavigation />
      <main className="flex-1 overflow-auto">
        {children}
      </main>
    </div>
  </SidebarProvider>
);
}

With Page Section

Layout with Page Header

Combining layout with page section headers

function DashboardPage() {
return (
  <SidebarProvider mainNavItems={mainNavItems}>
    <div className="flex h-screen">
      <SideNavigation />
      <main className="flex-1 overflow-auto bg-bg">
        <PageSection
          pageTitle="Dashboard"
          primaryAction={{
            label: 'Create Campaign',
            onClick: () => {},
          }}
        />
        <div className="p-6">
          {/* Page content */}
        </div>
      </main>
    </div>
  </SidebarProvider>
);
}

Standalone Secondary Panel

Secondary Panel Only

Use SidebarPanel independently for custom layouts

function CustomLayout() {
const [isOpen, setIsOpen] = useState(true);
const [activeItem, setActiveItem] = useState('overview');

return (
  <div className="flex h-screen">
    <SidebarPanel
      title="Settings"
      isOpen={isOpen}
      onToggle={() => setIsOpen(!isOpen)}
    >
      <SidebarItem
        label="Overview"
        iconOutlined={MdOutlineDashboard}
        iconFilled={MdDashboard}
        isActive={activeItem === 'overview'}
        onClick={() => setActiveItem('overview')}
      />
      <SidebarItem
        label="Account"
        iconOutlined={MdPeopleOutline}
        iconFilled={MdPeople}
        isActive={activeItem === 'account'}
        onClick={() => setActiveItem('account')}
      >
        <SidebarSubItem
          label="Profile"
          isActive={activeItem === 'profile'}
          onClick={() => setActiveItem('profile')}
        />
        <SidebarSubItem
          label="Security"
          isActive={activeItem === 'security'}
          onClick={() => setActiveItem('security')}
        />
      </SidebarItem>
    </SidebarPanel>
    <main className="flex-1">
      {/* Content */}
    </main>
  </div>
);
}

Custom Configuration

Provider Configuration

Customize sidebar behavior with config options

<SidebarProvider
mainNavItems={mainNavItems}
config={{
  defaultSecondaryOpen: true,
  animationDuration: 300,
  collapsedWidth: 64,
  expandedWidth: 224,
}}
>
<div className="flex h-screen">
  <SideNavigation />
  <main className="flex-1">{children}</main>
</div>
</SidebarProvider>

Layout Patterns

Dashboard Layout

function DashboardLayout({ children }) {
  return (
    <SidebarProvider mainNavItems={dashboardNav}>
      <div className="flex h-screen bg-bg">
        <SideNavigation />
        <div className="flex-1 flex flex-col overflow-hidden">
          <PageSection pageTitle="Dashboard" />
          <main className="flex-1 overflow-auto p-6">
            {children}
          </main>
        </div>
      </div>
    </SidebarProvider>
  );
}

Settings Layout

function SettingsLayout({ children }) {
  const [activeSection, setActiveSection] = useState('general');

  return (
    <div className="flex h-screen">
      <SidebarPanel title="Settings" isOpen={true}>
        <SidebarItem
          label="General"
          isActive={activeSection === 'general'}
          onClick={() => setActiveSection('general')}
        />
        <SidebarItem
          label="Security"
          isActive={activeSection === 'security'}
          onClick={() => setActiveSection('security')}
        />
        <SidebarItem
          label="Notifications"
          isActive={activeSection === 'notifications'}
          onClick={() => setActiveSection('notifications')}
        />
      </SidebarPanel>
      <main className="flex-1 p-6">
        {children}
      </main>
    </div>
  );
}

Best Practices

Use SidebarProvider at root

Wrap your entire application or layout section with SidebarProvider for consistent state management.

Organize navigation logically

Group related items together and use clear, descriptive labels.

Persist sidebar state

Save the user's sidebar open/closed preference in local storage.

Use icons consistently

Use Material Design icons with outlined/filled variants for visual consistency.

Don't overcrowd navigation

Limit primary navigation to 5-7 items. Use secondary panels for additional items.

Don't nest too deeply

Keep navigation depth to 3 levels maximum for usability.

Props

SidebarProvider

PropTypeDefaultDescription
mainNavItemsMainNavItem[]-Primary navigation items with icons and paths
configSidebarConfig-Configuration options for sidebar behavior
classNamestring-Additional className for wrapper
childrenReactNode-Application content

SideNavigation

PropTypeDefaultDescription
classNamestring-Additional className
interface MainNavItem {
  id: string;
  label: string;
  iconOutlined: IconType;
  iconFilled: IconType;
  path: string;
  secondaryItems?: SecondaryNavItem[];
}

interface SecondaryNavItem {
  id: string;
  label: string;
  path: string;
  subItems?: SubNavItem[];
}

SidebarConfig

interface SidebarConfig {
  defaultSecondaryOpen?: boolean;
  animationDuration?: number;
  collapsedWidth?: number;
  expandedWidth?: number;
}

Accessibility

Semantic Navigation

The layout system uses proper semantic HTML with <nav> elements and ARIA landmarks for screen reader navigation.

  • Primary and secondary navigation use separate <nav> elements with distinct aria-labels
  • All interactive elements are keyboard accessible
  • Focus is properly managed when toggling panels
  • Active states are communicated to assistive technology
  • Skip links should be added to bypass navigation for keyboard users