Header & Sidebar
Header and Sidebar are consumed via the Layout component — you do not render them directly. Pass their configuration through Layout's headerProps and sidebarProps.
Header
The top navigation bar. It contains the application switcher, breadcrumbs, organization context switcher, and the user account menu (profile, theme customisation, logout).
Key headerProps fields
| Field | Type | Description |
|---|---|---|
userInfo | { email, username } | Shown in the account menu |
onLogout | () => void | Called when the user clicks Logout |
onViewProfileClick | () => void | Called when the user clicks View Profile |
appsQuery | { isLoading, error, data } | Applications list for the app-switcher |
breadcrumbsProps | BreadcrumbsProps | Menu items, active path, and navigate handler for breadcrumb generation |
organizationContextProps | OrgContextProps | Organization list, current org, and change handler |
textOverrides | object | Translatable labels for all header UI strings |
onDrawerToggle | () => void | Internal — wired by Layout. Pass () => {} when composing manually |
Example
src/layout/AppLayout.tsx
headerProps={{
userInfo: {
email: profileQuery.data?.body?.email || "",
username: profileQuery.data?.body?.userName || "",
},
onLogout: handleLogout,
onViewProfileClick: () => navigate("/profile"),
appsQuery: {
isLoading: appsQuery.isLoading,
error: appsQuery.error,
data: (appsQuery.data?.body as any) || [],
},
breadcrumbsProps: {
menuItems: mappedMenuItems,
onNavigate: (path) => navigate(path),
currentPathname: pathname,
initBreadcrumbs: [
{ label: t("common.dashboard"), path: "/dashboard", icon: <DashboardIcon /> },
],
actionsLabel: {
edit: t("common.edit"),
view: t("common.view"),
new: t("common.new"),
},
},
organizationContextProps: {
organizations: orgsQuery.data?.body?.map((org) => ({
id: org.id || 0,
name: language === "en" ? org.englishName || "" : org.arabicName || "",
})) || [],
currentOrganization: currentOrg
? { id: currentOrg.id || 0, name: language === "en" ? currentOrg.englishName : currentOrg.arabicName }
: null,
isLoading: orgsQuery.isLoading,
error: orgsQuery.error,
onOrganizationChange: handleOrganizationChange,
textOverrides: {
switchOrganization: t("authorization.organization"),
currentOrganization: t("authorization.currentOrganization"),
noOrganizations: t("authorization.noOrganizations"),
},
},
textOverrides: {
accountInfo: t("appLayout.accountInfo"),
themeCustomization: t("appLayout.themeCustomization.title"),
accountMenuTextOverrides: {
profile: t("appLayout.profile"),
logout: t("common.logout"),
darkMode: t("appLayout.darkMode"),
lightMode: t("appLayout.lightMode"),
},
},
onDrawerToggle: () => {},
}}
Sidebar
The collapsible side navigation drawer. Reads menu items from a menuQuery (RTK Query result) and a local menuItems map, then renders labelled nav entries with icons. Highlights the active route automatically from currentPath.
Key sidebarProps fields
| Field | Type | Description |
|---|---|---|
currentPath | string | Active route pathname — used to highlight the current nav item |
language | string | Current language ("en" or "ar") for label lookup |
onNavigate | (path) => void | Called when a nav item is clicked |
menuQuery | { isLoading, error, data } | Remote menu from your API |
menuItems | Record<string, any> | Local icon + translation-key map keyed by route path |
sidebarLogoProps | { appName, appIcon } | App name and icon shown at the top of the sidebar |
open | boolean | Controlled open/closed (managed by Layout internally) |
onClose | () => void | Called when the sidebar requests to close (managed by Layout) |
contextSwitcherProps | ContextSwitcherProps | App-context switcher (shows available apps, handles switching) |
appsQuery | { isLoading, error, data } | Applications list for the context switcher |
textOverrides | object | { appName, appVersion, mainMenuHeader } |
Example
src/layout/AppLayout.tsx
sidebarProps={{
currentPath: pathname,
language: language,
onNavigate: (path) => navigate(path),
menuQuery: {
isLoading: menuQuery.isLoading,
error: menuQuery.error,
data: menuQuery.data?.body || [],
},
menuItems: menuItems as Record<string, any>,
sidebarLogoProps: {
appName: "MyApp",
appIcon: <DnsIcon fontSize="small" />,
},
open: true,
onClose: () => {},
textOverrides: {
appName: "MyApp",
appVersion: "1.0.0",
mainMenuHeader: t("common.mainMenu"),
},
contextSwitcherProps: {
contexts: appsQuery.data?.body?.map((app) => ({
id: app.id || 0,
name: app.name || "Unknown",
icon: <AppIcon />,
})) || [],
initialContext: {
id: currentApp?.id || 0,
name: currentApp?.name || "Unknown",
icon: <AppIcon />,
},
universalContext: {
id: config.applicationClientId,
name: t("common.allApps"),
icon: <AppsIcon sx={{ fill: "#fff" }} />,
},
menuLevel: 2,
onMenuLevelChange: handleMenuLevelChange,
onContextLevelChange: handleContextLevelChange,
textOverrides: {
contextDropdown: t("common.currentApp"),
},
},
appsQuery: {
isLoading: appsQuery.isLoading,
error: appsQuery.error,
data: (appsQuery.data?.body as any) || [],
},
}}
See also
- Layout — full wiring example
- Page Layouts