Filter by title

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 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:

src/
├── components/
│   ├── layout/
│   └── ui/
├── lib/
│   ├── api/
│   ├── auth/
│   ├── i18n/
│   ├── routing/
│   └── theme/
└── pages/

Adding a Page

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.

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:

: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:

: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:

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.

Modifying the Sidebar Menu

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>

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/<feature>/.

Keep generic primitives in components/ui and business-specific components close to the feature or page that owns them.

See Also

Contributors


Last updated: May 06, 2026 Edit this page on GitHub

Was this page helpful?

Please make a selection.

To help us improve, please share your reason for the negative feedback in the field below.

Please enter a note.

Thank you for your valuable feedback!

Please note that although we cannot respond to feedback, our team will use your comments to improve the experience.

ABP Community Talks
Low-Code, High Precision
13 Aug, 17:00
Online
Watch the Event
ABP Live Webinar
Webinar Calendar Webinar Calendar
Discover
ABP Platform
Register Now
Oct 01
Thursday,
17:00 UTC
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.