Layout
Main
The page body of Max's app shell: a <main> with the standard page padding and, by default, a centred 7xl width.
Guidelines#
Use it for the top-level content of every page inside the authenticated layout, below Header.
What you provide:
fixed?: boolean: makes the page a growing flex column withoverflow-hiddenand setsdata-layout="fixed", which lets the shell's inset take the full viewport height. Use it for full-height tools.fluid?: boolean: drops the max width.className,ref, and any<main>attribute.
Anatomy: px-4 py-6. Unless fluid, the page gets mx-auto w-full max-w-7xl once the @container/content it sits in reaches the 7xl container size. That container is the shell's SidebarInset, so outside the shell the max width never applies.
Patterns in Max:
- Scrolling pages such as Notifications use a plain
<Main>. - Full-bleed workspaces (calendar, crew, meeting assistant) use
<Main fixed fluid className="p-0">. - Prospects uses
<Main className="p-0">and lets the page set its own padding.
Don't nest Main, and don't add another max-width wrapper inside it.
Facts#
| Group | Layout |
|---|---|
| Product | Max |
| Global | window.DigitalCrew.Main |
| Source | max-agent: src/components/layout/main.tsx |
| Import in the app | import { Main } from "@/components/layout/main"; |
API#
TypeScript declarations emitted from src/components/layout/main.tsx.
type MainProps = React.HTMLAttributes<HTMLElement> & {
fixed?: boolean;
fluid?: boolean;
ref?: React.Ref<HTMLElement>;
};
export declare function Main({ fixed, className, fluid, ...props }: MainProps): JSX.Element;Example#
The code of the preview above: plain React.createElement against window.DigitalCrew, with realistic data.
<div id="root" class="p-6"></div>
<script>
(function () {
var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
function Stat(props) {
return h(DC.Card, { className: "gap-1 py-4" },
h(DC.CardContent, { className: "px-4" },
h("p", { className: "text-xs text-muted-foreground" }, props.label),
h("p", { className: "text-xl font-semibold tabular-nums" }, props.value)));
}
function App() {
// The shell's content pane is the @container/content that Main's max width keys off.
return h("div", { className: "@container/content overflow-hidden rounded-[10px] border border-glass bg-background/70" },
h("div", { className: "flex h-14 items-center gap-2 border-b border-border/60 px-4 text-sm text-muted-foreground" },
h(I.Bell, { className: "size-4" }), "Header"),
h(DC.Main, null,
h("div", { className: "space-y-4" },
h("div", { className: "flex items-center justify-between" },
h("h1", { className: "text-2xl font-semibold" }, "Notifications"),
h(DC.Button, { variant: "outline", size: "sm" }, "Mark all as read")),
h("div", { className: "grid grid-cols-3 gap-4" },
h(Stat, { label: "Unread", value: "7" }),
h(Stat, { label: "Replies today", value: "12" }),
h(Stat, { label: "Meetings booked", value: "3" })),
h("p", { className: "text-sm text-muted-foreground" }, "Max booked a meeting with Claire Dubois, CFO at Northwind Traders, for Thursday at 10:00."))));
}
ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>