```json
//[doc-seo]
{
"Description": "Learn how to customize ABP React UI applications, including pages, themes, sidebar navigation, and the user menu."
}
```
# Customization
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](./admin-console.md) for details.
## General Customization
Application pages live under `src/pages/`. The template includes practical references:
- **Users page**: a simple page that lists users and links to the Admin Console for full user and role management.
- **Books page**: a full CRUD sample when the sample CRUD option is selected during solution creation. It demonstrates TanStack Query, forms, Zod validation, dialogs, tables, permissions, and toast notifications.
Shared UI and infrastructure live under:
```text
src/
├── components/
│ ├── layout/
│ └── ui/
├── lib/
│ ├── api/
│ ├── auth/
│ ├── i18n/
│ ├── routing/
│ └── theme/
└── pages/
```
## Adding a Page
Create a page under `src/pages/`:
```tsx
export function ReportsPage() {
return (
Reports
)
}
```
Register it with TanStack Router in `src/routes/router.tsx`:
```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.
## Theming
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`:
```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.
## Changing Theme Colors
To make a quick theme change, edit the CSS variables in `src/styles/globals.css`:
```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 Switcher
Theme mode is handled by `src/lib/theme/ThemeProvider.tsx`. It supports:
- `light`
- `dark`
- `system`
The header cycles through the allowed modes:
```tsx
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
}
```
To remove the switcher or replace it with a dropdown, edit `src/components/layout/Header.tsx`.
## Modifying the Sidebar Menu
Sidebar navigation is defined in `src/lib/routing/route-config.ts`.
Add a menu item:
```ts
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`:
```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. |
## Sidebar vs User Menu
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:
```tsx
{t('MyAccount::Preferences')}
```
## Customizing UI Components
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:
- Change button variants in `src/components/ui/button.tsx`.
- Change dialog structure in `src/components/ui/dialog.tsx`.
- Add a new reusable component under `src/components/ui/`.
- Add feature-specific components under `src/components//`.
Keep generic primitives in `components/ui` and business-specific components close to the feature or page that owns them.
## See Also
- [Components](./components/index.md)
- [Permission Management](./permission-management.md)
- [Admin Console](./admin-console.md)