npm install @marmoui/uiyarn add @marmoui/uipnpm add @marmoui/uibun add @marmoui/uiImport the PageSection components from the package:
import { PageSection, PageSectionWizard } from '@marmoui/ui';Display a standalone page title
<div className="w-full border border-border rounded-lg overflow-hidden">
<PageSection pageTitle="Dashboard" />
</div>Breadcrumbs are not a mirror of sidebar navigation. Use them only when the page
has real hierarchy or parent context, such as analytics for a specific module
(campaign, course, product), a single contact page, a file-manager folder path,
or a folder that groups related modules. Use pageTitle for ordinary sidebar
destinations.
Show hierarchical navigation with breadcrumbs
<div className="w-full border border-border rounded-lg overflow-hidden">
<PageSection
breadcrumbs={[
{ label: 'Home', href: '#' },
{ label: 'Projects', href: '#' },
{ label: 'Website Redesign' },
]}
/>
</div>Add primary and secondary action buttons
<div className="w-full border border-border rounded-lg overflow-hidden">
<PageSection
pageTitle="User Management"
primaryAction={{ label: 'Add User', onClick: () => {} }}
secondaryActions={[
{ label: 'Import', onClick: () => {} },
{ label: 'Export', onClick: () => {} },
]}
otherActions={[
{ label: 'Settings', onClick: () => {} },
{ label: 'Help', onClick: () => {} },
]}
/>
</div>PageSection has five variants that match the Figma Page Section component. Use AppLayout to pick the layout + variant pair automatically, or set variant manually.
| Variant | Figma | Typical layout |
|---|---|---|
default | Default | sidebar-collapsible — brand + search + utilities |
workspace | Layout 2 | sidebar-hidden — logo-in-toggle + search; nav row under header |
global | Layout 3 | top-nav — horizontal nav with mega menus |
compact | Layout 4 | dual-sidebar — title/breadcrumbs + actions only (default) |
profile | Profile Header | User profile pages |
Breadcrumbs always render on a single line (including the last crumb) across every variant.
See the App layouts pattern for the full selection flow.
Figma Default variant for collapsible sidebar apps
<SidebarProvider mainNavItems={[]} config={{ defaultSecondaryOpen: true }}>
<div className="w-full overflow-hidden rounded-lg border border-border">
<PageSection
variant="default"
breadcrumbs={[{ label: 'Projects' }]}
searchPlaceholder="Search"
/>
</div>
</SidebarProvider>Figma Layout 3 for top-nav apps
<div className="w-full overflow-hidden rounded-lg border border-border">
<PageSection
variant="global"
globalNavItems={[
{ label: 'Dashboards', hasMenu: true, isActive: true },
{ label: 'Components', hasMenu: true },
{ label: 'Templates', hasMenu: true },
]}
/>
</div>Figma Layout 4 for dual-sidebar apps
<SidebarProvider mainNavItems={[]} config={{ defaultSecondaryOpen: false }}>
<div className="w-full overflow-hidden rounded-lg border border-border">
<PageSection variant="compact" pageTitle="Projects" />
</div>
</SidebarProvider>Add contextual actions to the last breadcrumb item
<div className="w-full border border-border rounded-lg overflow-hidden">
<PageSection
breadcrumbs={[
{ label: 'Campaigns', href: '#' },
{
label: 'Summer Sale Campaign',
actions: [
{ label: 'Rename', icon: <MdOutlineEdit />, onClick: () => {} },
{ label: 'Duplicate', icon: <MdOutlineCopyAll />, onClick: () => {} },
{ label: 'Archive', icon: <MdOutlineArchive />, onClick: () => {} },
{ label: 'Delete', icon: <MdOutlineDelete />, isDelete: true, onClick: () => {} },
],
},
]}
primaryAction={{ label: 'Save Changes', onClick: () => {} }}
/>
</div>PageSectionWizard is designed for multi-step form flows with editable titles and step indicators.
Step indicator for multi-step forms
<SidebarProvider mainNavItems={[]} config={{ defaultSecondaryOpen: false }}>
<div className="w-full border border-border rounded-lg overflow-hidden">
<PageSectionWizard
title="Create Campaign"
currentStep={1}
totalSteps={4}
steps={[
{ id: 'details', label: 'Details' },
{ id: 'content', label: 'Content' },
{ id: 'audience', label: 'Audience' },
{ id: 'review', label: 'Review' },
]}
/>
</div>
</SidebarProvider>Allow users to edit the wizard title inline
<SidebarProvider mainNavItems={[]} config={{ defaultSecondaryOpen: false }}>
<div className="w-full border border-border rounded-lg overflow-hidden">
<PageSectionWizard
title={title}
onTitleChange={setTitle}
onTitleChangeEnd={(newTitle) => console.log('Saved:', newTitle)}
titlePlaceholder="Untitled Campaign"
currentStep={0}
totalSteps={3}
steps={[
{ id: 'details', label: 'Details' },
{ id: 'content', label: 'Content' },
{ id: 'review', label: 'Review' },
]}
/>
</div>
</SidebarProvider>Click completed steps to navigate back
<SidebarProvider mainNavItems={[]} config={{ defaultSecondaryOpen: false }}>
<div className="w-full border border-border rounded-lg overflow-hidden">
<PageSectionWizard
title="Campaign Builder"
currentStep={currentStep}
totalSteps={steps.length}
steps={steps}
onStepClick={setCurrentStep}
/>
</div>
</SidebarProvider>Minimal step indicator without labels
<SidebarProvider mainNavItems={[]} config={{ defaultSecondaryOpen: false }}>
<div className="w-full border border-border rounded-lg overflow-hidden">
<PageSectionWizard
title="Setup Wizard"
currentStep={2}
totalSteps={5}
/>
</div>
</SidebarProvider>Replace step indicators with custom content
<SidebarProvider mainNavItems={[]} config={{ defaultSecondaryOpen: false }}>
<div className="w-full border border-border rounded-lg overflow-hidden">
<PageSectionWizard
title="Import Contacts"
stepsContent={
<div className="flex items-center gap-2">
<Button variant="secondary" size="sm">Cancel</Button>
<Button variant="primary" size="sm">Import 234 Contacts</Button>
</div>
}
/>
</div>
</SidebarProvider>Use breadcrumbs for real hierarchy: module analytics detail pages, single contact pages, file-manager folders/files, and folders that group related modules.
Sidebar navigation and breadcrumbs solve different problems. A top-level sidebar destination usually needs pageTitle, not breadcrumbs.
Show at most 1-2 primary actions. Use the overflow menu for additional actions.
The primary action should be the most important action on the page.
Use PageSectionWizard when guiding users through a sequential process.
Keep breadcrumb labels concise. Truncate if necessary.
Use one consistent page header pattern throughout your application.
primaryAction, never in the page body. Do not render a toolbar row under the header with the primary button (e.g. "Import CSV", "Create contact"). Pass it as primaryAction={{ label: 'Import CSV', onClick: … }} so it renders inside the header, aligned with the title.<PageSection pageTitle="…" primaryAction={…} /> and place page content in a sibling element beneath it. PageSection is not a wrapper.<PageSection>…</PageSection>. That pattern ignores the component's real prop contract (pageTitle, breadcrumbs, primaryAction, secondaryActions, otherActions) and will not render correctly.primaryAction={{ label: 'Save', onClick: () => {} }} — not primaryAction={<Button>Save</Button>}.title / subtitle / children props. Those belong to an older, private PageSection component that is no longer part of @marmoui/ui. Use pageTitle and breadcrumbs instead.| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'workspace' | 'global' | 'compact' | 'profile' | 'compact' | Top bar layout — see App layouts |
pageTitle | string | - | Standalone page title (alternative to breadcrumbs) |
breadcrumbs | PageSectionBreadcrumbItem[] | - | Array of breadcrumb items |
primaryAction | PageSectionActionItem | - | Primary CTA button configuration |
secondaryActions | PageSectionSecondaryActionItem[] | - | Secondary action buttons |
otherActions | PageSectionActionItem[] | - | Overflow menu actions |
showSidebarToggle | boolean | true | Show sidebar toggle when sidebar is collapsed |
globalNavItems | PageSectionGlobalNavItem[] | - | Horizontal nav links (variant="global"); items with hasMenu open a mega menu populated from menu groups |
logoInToggle | boolean | false | Render the brand logo inside the sidebar toggle button (Layout 2); hides the standalone brand |
searchPlaceholder | string | 'Search' | Search input placeholder (default / workspace) |
brandLabel | string | 'Marmo' | Brand text beside logo |
profile | PageSectionProfile | - | Profile header content (variant="profile") |
className | string | - | Additional className |
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | - | Wizard title |
onTitleChange | (newTitle: string) => void | - | Makes title editable when provided |
onTitleChangeEnd | (newTitle: string) => void | - | Called when title editing ends |
titlePlaceholder | string | 'Untitled' | Placeholder when title is empty |
currentStep | number | - | Current step index (0-based) |
totalSteps | number | - | Total number of steps |
steps | WizardStepItem[] | - | Array of step definitions |
onStepClick | (stepIndex: number) => void | - | Called when a step is clicked |
showSidebarToggle | boolean | true | Show sidebar toggle when sidebar is collapsed |
stepsContent | ReactNode | - | Custom content for steps area |
Navigation Landmarks
PageSection uses proper semantic HTML with navigation landmarks for breadcrumbs and heading elements for titles.
<nav> with proper ARIA labels