Navigation
Header
The app's top bar: a sidebar toggle and a divider, followed by whatever you pass in.
Guidelines#
Use it for the single header at the top of the authenticated layout. In Max its children are the search box, a flex-1 spacer, the notification bell, ThemeSwitcher and the dock for the floating Max bubble.
What you provide:
children.fixed?: boolean: makes the header sticky at the top and adds a shadow once the page has scrolled more than 10px.className,ref, and any<header>attribute.
It must sit inside SidebarProvider, because its trigger reads the sidebar context.
Anatomy:
z-50,h-14(56px) andsm:h-16(64px), the height of a desktop title bar.- The inner row is
border-b border-border/60 px-3 sm:px-4withgap-2 sm:gap-3. - The
SidebarTriggeruses the outline variant and is hidden belowmd: on phones the tab bar's More button opens the menu. - A vertical
Separator(h-6) shows frommdup. - When
fixedand scrolled, abg-background/20 backdrop-blur-lglayer sits behind the row.
Behaviour: a passive scroll listener on the document tracks the offset. The shadow and blur apply only when fixed.
Don't add a second header inside a page. Page actions belong in the page, under the header.
Facts#
| Group | Navigation |
|---|---|
| Product | Max |
| Global | window.DigitalCrew.Header |
| Source | digitalcrew-orchestrator: components/ui/container-scroll-animation.tsx |
| Import in the app | import { Header } from "@/components/ui/container-scroll-animation"; |
API#
TypeScript declarations emitted from components/ui/container-scroll-animation.tsx (the module also exports ContainerScroll).
export declare const ContainerScroll: ({ titleComponent, children, }: {
titleComponent: string | React.ReactNode;
children: React.ReactNode;
}) => any;
export declare const Header: ({ translate, titleComponent }: {
translate: MotionValue<number>;
titleComponent: React.ReactNode;
}) => any;
export declare const Card: ({ rotate, scale, children, }: {
rotate: MotionValue<number>;
scale: MotionValue<number>;
translate: MotionValue<number>;
children: React.ReactNode;
}) => any;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 App() {
// Header reads the sidebar context for its trigger, so it needs a SidebarProvider above it.
return h(DC.SidebarProvider, { className: "min-h-0" },
h("div", { className: "w-full overflow-hidden rounded-[10px] border border-glass bg-background/70" },
h(DC.Header, null,
h(DC.Button, { variant: "outline", size: "sm", className: "h-8 w-56 justify-start bg-muted/25 text-muted-foreground" },
h(I.Search), "Search..."),
h("div", { className: "flex-1" }),
h(DC.Button, { variant: "ghost", size: "icon", className: "relative rounded-full", "aria-label": "Notifications" },
h(I.Bell), h("span", { className: "absolute top-2 right-2 size-2 rounded-full bg-primary" })),
h(DC.ThemeSwitcher)),
h("div", { className: "px-4 py-4 text-sm text-muted-foreground" }, "Page content scrolls under the header; with fixed it sticks and gains a shadow past 10px.")));
}
ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>