Layout
The Layout component is the outermost shell. It composes Header, Sidebar, and the page content area into a responsive full-height layout. You wire it through headerProps and sidebarProps — you do not render Header or Sidebar directly.
Import
import { Layout } from "@xocialive/ui-components/layout";
Props
| Prop | Type | Description |
|---|---|---|
children | ReactNode | Page content area |
headerProps | HeaderProps | All header configuration |
sidebarProps | SidebarProps | All sidebar configuration |
Usage
src/layout/AppLayout.tsx
import React from "react";
import { Outlet, useNavigate, useLocation } from "react-router-dom";
import { Layout } from "@xocialive/ui-components/layout";
import { useLanguage } from "@xocialive/ui-components/contexts";
import DnsIcon from "@mui/icons-material/Dns";
const AppLayout: React.FC = () => {
const navigate = useNavigate();
const { pathname } = useLocation();
const { language } = useLanguage();
return (
<Layout
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: () => {},
}}
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"),
},
appsQuery: {
isLoading: appsQuery.isLoading,
error: appsQuery.error,
data: (appsQuery.data?.body as any) || [],
},
}}
>
<Outlet />
</Layout>
);
};
export default AppLayout;
Route setup
Wrap the AppLayout as a parent route so nested routes render inside it:
src/routes/index.tsx
import Loadable from "react-loadable";
import { lazy } from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import AppLayout from "@/layout/AppLayout";
const ItemsRoutes = Loadable({
loader: () => import("@/routes/ItemsRoutes"),
loading: () => null,
});
<BrowserRouter>
<Routes>
<Route path="/" element={<AppLayout />}>
<Route path="items/*" element={<ItemsRoutes />} />
</Route>
</Routes>
</BrowserRouter>;
See also
- Header & Sidebar — individual prop references
- Page Layouts —
PageListViewandPageItemView