App Layout
v0.2.0Full page shell: header, collapsible desktop sidebar, and sheet-based mobile drawer composed around your page content.
Install
npx shadcn@latest add @signalos/app-layoutRequires a configured @signalos registry and a valid SIGNALOS_REGISTRY_TOKEN - get access. Registry dependencies (@signalos/tokens, @signalos/utils) are pulled automatically.
Preview
Example & code
app-layout.example.tsx
import { useState } from "react"
import { Inbox, LayoutDashboard, Settings } from "lucide-react"
import { AppLayout } from "@/components/widgets/app-layout/AppLayout"
import type { AppLayoutNavItem } from "@/components/widgets/app-layout/AppLayout.types"
const navigationItems: AppLayoutNavItem[] = [
{
id: "dashboard",
label: "Dashboard",
collapsedLabel: "Home",
href: "#/dashboard",
icon: LayoutDashboard,
active: true,
},
{
id: "feed",
label: "Signal Feed",
collapsedLabel: "Feed",
href: "#/feed",
icon: Inbox,
},
{
id: "settings",
label: "Settings",
href: "#/settings",
icon: Settings,
section: "bottom",
},
]
export default function Example() {
const [collapsed, setCollapsed] = useState(false)
return (
<AppLayout
navigationItems={navigationItems}
logo={
<span className="text-lg font-semibold text-sidebar-foreground">
Acme Ops
</span>
}
header={<span className="text-sm font-medium">Dashboard</span>}
isSidebarCollapsed={collapsed}
onSidebarCollapsedChange={setCollapsed}
>
<p className="text-sm text-muted-foreground">
Route content renders here.
</p>
</AppLayout>
)
}
Props
AppLayoutNavItem
| Prop | Type | Default | Description |
|---|---|---|---|
| id* | string | - | |
| label* | string | - | |
| href* | string | - | |
| icon | ComponentType<{ className?: string | undefined; }> | undefined | - | |
| section | "main" | "bottom" | undefined | - | |
| active | boolean | undefined | - | |
| collapsedLabel | string | undefined | - |
AppLayoutLinkComponentProps
| Prop | Type | Default | Description |
|---|---|---|---|
| href* | string | - | |
| className | string | undefined | - | |
| onClick | (() => void) | undefined | - | |
| aria-current | "page" | undefined | - | |
| data-testid | string | undefined | - | |
| children | ReactNode | - |
AppLayoutProps
| Prop | Type | Default | Description |
|---|---|---|---|
| navigationItems* | AppLayoutNavItem[] | - | |
| children* | ReactNode | - | |
| logo | ReactNode | - | |
| header | ReactNode | - | |
| isSidebarCollapsed | boolean | undefined | - | |
| onSidebarCollapsedChange | ((collapsed: boolean) => void) | undefined | - | |
| isMobileNavOpen | boolean | undefined | - | |
| onMobileNavOpenChange | ((open: boolean) => void) | undefined | - | |
| onNavigate | ((item: AppLayoutNavItem) => void) | undefined | - | |
| LinkComponent | ComponentType<AppLayoutLinkComponentProps> | undefined | - | Component used to render navigation links, e.g. Next.js `Link` or a router-aware anchor. Defaults to a plain `<a>` tag (full page reload). |
| className | string | undefined | - | |
| data-testid | string | undefined | - | Test identifier rendered as `data-testid` on the root element. |
npm dependencies
lucide-react@^1.7.0Changelog
app-layout
0.2.0
- Breaking: rename the
testIdprop todata-testidto match the rest of the registry and the DOM attribute name.
0.1.2
- Removed the
next/linkdependency from sidebar/mobile navigation. Added an optionalLinkComponentprop so host apps can supply their own router-aware link (e.g. Next.jsLink); defaults to a plain<a>tag when not provided. - Content sync fix to bring source in line with published registry payload.
0.1.0
- Initial release: full shell composition (header + collapsible sidebar + sheet-style
mobile drawer + main content area) around a single
<AppLayout>component. Migrated and renamed from theapp-shell2scaffold; internalHeader/Sidebar/MobileNav/NavListpieces were inlined intoAppLayout.tsxto match the registry's flat per-item file contract.