docs/en/framework/ui/react/customization.md
//[doc-seo]
{
"Description": "Learn how to customize ABP React UI applications, including pages, themes, sidebar navigation, and the user menu."
}
The React app generated by ABP is fully owned by your solution. All source code is available, so you can change pages, components, routes, themes, menus, API calls, and layout behavior just like in any other React application.
This page focuses on the main developer-owned React app. The same general approach applies to the public-web React app if your solution includes one. The Admin Console is an ABP-managed administration surface; see Admin Console for details.
Application pages live under src/pages/. The template includes practical references:
Shared UI and infrastructure live under:
src/
├── components/
│ ├── layout/
│ └── ui/
├── lib/
│ ├── api/
│ ├── auth/
│ ├── i18n/
│ ├── routing/
│ └── theme/
└── pages/
Create a page under src/pages/:
export function ReportsPage() {
return (
<div className="space-y-6">
<h1 className="text-3xl font-bold tracking-tight">Reports</h1>
</div>
)
}
Register it with TanStack Router in src/routes/router.tsx:
const reportsRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/reports',
component: ReportsPage,
beforeLoad: createPermissionGuard('MyProjectName.Reports'),
})
const routeTree = rootRoute.addChildren([
indexRoute,
reportsRoute,
])
Use authGuard for pages that only require authentication and createPermissionGuard for pages that require a permission.
The React template uses shadcn/ui-style components, Radix UI primitives, Tailwind CSS, and CSS variables.
Theme tokens are defined in src/styles/globals.css:
:root {
--background: oklch(0.978 0.003 264);
--foreground: oklch(0.205 0.008 264);
--primary: oklch(0.48 0.10 278);
--radius: 0.5rem;
}
.dark {
--background: oklch(0.16 0.004 264);
--foreground: oklch(0.92 0.005 264);
--primary: oklch(0.62 0.12 278);
}
ABP Studio's modern wizard can generate different shadcn theme color presets and light/dark/system theme behavior.
To make a quick theme change, edit the CSS variables in src/styles/globals.css:
:root {
--primary: oklch(0.623 0.188 259.6);
--primary-foreground: oklch(1 0 0);
}
Because the generated shadcn/ui components consume these variables through Tailwind tokens, the change applies across buttons, links, active sidebar entries, focus rings, and other components that use the primary color.
Theme mode is handled by src/lib/theme/ThemeProvider.tsx. It supports:
lightdarksystemThe header cycles through the allowed modes:
const THEME_CYCLE: Theme[] = ['light', 'dark', 'system']
function ThemeToggle() {
const { theme, resolvedTheme, setTheme } = useTheme()
function cycleTheme() {
const currentIndex = THEME_CYCLE.indexOf(theme)
const nextIndex = currentIndex < 0 ? 0 : (currentIndex + 1) % THEME_CYCLE.length
setTheme(THEME_CYCLE[nextIndex])
}
return <Button variant="ghost" size="icon" onClick={cycleTheme}>...</Button>
}
To remove the switcher or replace it with a dropdown, edit src/components/layout/Header.tsx.
Sidebar navigation is defined in src/lib/routing/route-config.ts.
Add a menu item:
import { BarChart3 } from 'lucide-react'
export const routeConfig: RouteConfigItem[] = [
{
path: '/reports',
nameKey: 'Menu:Reports',
icon: BarChart3,
order: 10,
requiredPolicy: 'MyProjectName.Reports',
},
]
Then add the localization key to src/locales/en.json:
{
"Menu:Reports": "Reports"
}
Use these properties depending on the menu item:
| Property | Use |
|---|---|
path | Internal route path or logical path for an external item. |
nameKey | Localization key shown in the sidebar. |
icon | Optional Lucide icon. |
order | Sorting order. |
requiredPolicy | Hide the item unless the permission is granted. |
requiresAuth | Hide the item unless the user is authenticated. |
externalHref | Open an external URL or another app, such as the Admin Console. |
children | Add nested sidebar items. |
Use the sidebar navigation for application pages and module entry points.
Use the user menu for account-specific actions, profile links, sessions, security logs, linked accounts, and logout. The user menu is implemented in src/components/layout/UserMenu.tsx.
Example user menu item:
<DropdownMenuItem asChild className="cursor-pointer">
<a href="/account/preferences">
<Settings className="size-4" />
{t('MyAccount::Preferences')}
</a>
</DropdownMenuItem>
shadcn/ui components are copied into your project under src/components/ui/. They are not black-box components from a package. You can edit them directly.
For example:
src/components/ui/button.tsx.src/components/ui/dialog.tsx.src/components/ui/.src/components/<feature>/.Keep generic primitives in components/ui and business-specific components close to the feature or page that owns them.