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