"Description": "Learn how to build modern web applications with ABP using React UI — a React-first approach with a dedicated Admin Console, built on Vite, shadcn/ui, Zod, and Axios."
"Description": "Learn how to build modern web applications with ABP React UI, including runtime configuration, authentication, Admin Console, shadcn/ui components, and testing."
}
}
```
```
# React UI
# React UI
## Introduction
ABP provides a **React UI** option for building modern, client-side web applications. React UI is part of the **modern template system** and is available with **ABP Studio v3.0+** through the Modern Wizard or with `abp new --modern` using [ABP CLI](../../../cli/index.md).
ABP provides a **React UI** option for building modern, client-side web applications. The React UI is part of the **modern template system** and is available when you create a solution through the **Modern Wizard** in [ABP Studio](../../../studio/index.md) or with `abp new --modern` using [ABP CLI](../../../cli/index.md).
React UI is not available in classic, non-modern templates. Use ABP Studio's modern template flow or `Volo.Abp.Studio.Cli` to create a React-based solution.
> React UI is **not** available in the classic (non-modern) templates. Use `Volo.Abp.Studio.Cli` or ABP Studio's modern template flow to create a React-based solution. The classic CLI path (`--old`) does not create modern React solutions.
## Technology Stack
The React UI is built on a modern, industry-standard stack:
The React UI template is built with:
| Technology | Purpose |
| Technology | Purpose |
|---|---|
|---|---|
| [Vite](https://vitejs.dev/) | Build tool and dev server |
| [Vite](https://vite.dev/) | Build tool and dev server |
The template also includes ABP-specific NPM packages:
When you create a modern solution with React UI, it contains two UI surfaces: **your React application** and the **ABP Admin Console**.
### React App (Your Application)
This is **your application** — the user-facing SPA that you own and customize freely. It comes with:
- A sample **Books CRUD page** when the template is generated with sample CRUD support, demonstrating how to build a full create/read/update/delete page with the ABP backend
- A plain **Users page** as a minimal reference
- Pre-configured authentication via OIDC against the ABP Auth Server
- Pre-configured HTTP client (Axios) with ABP API integration
This is where you build your business-specific pages and features.
The location of the React app differs by template type:
- **Layered (`app --modern`) and Single-layer (`app-nolayers --modern`)**: the React app lives in the `react/` folder at the solution root.
- **Microservice (`microservice --modern`)**: the React app lives at `apps/react/`.
### React Admin Console (`Volo.Abp.AdminConsole`)
The **ABP Admin Console** is a pre-built React application that provides all standard ABP module management pages. It is delivered via the `Volo.Abp.AdminConsole` NuGet package and requires no modification on your part — it is updated automatically when you update your ABP packages.
The Admin Console includes pages for:
- Users & Roles management
- Organization Units
- Settings
- Audit Logs
- OpenIddict (Application, Scope management)
- Language Management *(if included)*
- Text Template Management *(if included)*
- GDPR *(if included)*
- SaaS / Tenant Management *(if included)*
- And all other optional module pages based on your solution configuration
How the Admin Console is hosted also differs by template type:
- **Layered and Single-layer templates**: The `Volo.Abp.AdminConsole` package is added directly to your `*.HttpApi.Host` project. It serves the Admin Console React app at the `/admin-console/*` path of your backend (e.g., `https://localhost:44300/admin-console/`). There is no separate `apps/react-admin-console/` folder — the Admin Console UI is embedded in and served by the backend.
- **Microservice template**: The Admin Console runs as a standalone React app at `apps/react-admin-console/`, served through the Web Gateway (YARP) alongside the main React app.
In both cases the Admin Console is accessible from the main React app via a navigation link.
Install or update `Volo.Abp.Studio.Cli`, then pass the `--modern` flag to `abp new`:
````bash
# Layered app with React UI (default when --modern is used)
abp new Acme.BookStore --template app --modern
# Single-layer app with React UI
abp new Acme.BookStore --template app-nolayers --modern
# Microservice solution with React UI + React Admin Console
abp new Acme.BookStore --template microservice --modern
````
The `react` UI framework is the default when `--modern` is specified. You can also pass it explicitly:
````bash
abp new Acme.BookStore --template app --modern --ui-framework react
````
To create a solution without any UI (API-only backend):
````bash
A modern React solution contains two UI surfaces:
abp new Acme.BookStore --template app --modern --ui-framework no-ui
````
See the [ABP CLI documentation](../../../cli/index.md#modern-templates) for the full list of modern templates, supported UI/mobile combinations, and modern-only options like `--shadcn-theme`, `--admin-password`, `--modular`, and `--services`.
- **Your React application**: the developer-owned SPA where you build application-specific pages and features.
- **ABP Admin Console**: the React-based administration UI for ABP modules.
### Using ABP Studio
The Admin Console is provided by the `Volo.Abp.AdminConsole` NuGet package in layered and single-layer templates. In microservice templates, it is also generated as a separate `apps/react-admin-console/` app and served through the Web Gateway.
Open ABP Studio and use the **New Solution** wizard. Choose the modern template flow, select the solution type you want to create, and use **React** as the UI framework. The wizard shows the options supported by the selected modern template and generates the solution with the same modern template system used by `abp new --modern`.
See [Admin Console](./admin-console.md) for hosting, module discovery, and permission details.
## Solution Structure
## Solution Structure
The layout of the React-related files depends on the template type.
The React app location depends on the modern template type:
### Layered and Single-layer Templates
- **Layered (`app --modern`) and single-layer (`app-nolayers --modern`)**: the React app lives in the `react/` folder at the solution root.
- **Microservice (`microservice --modern`)**: the React app lives at `apps/react/`.
For `app --modern` and `app-nolayers --modern`, the React app lives in the `react/` folder at the solution root. The Admin Console is embedded in the backend via the `Volo.Abp.AdminConsole` NuGet package; there is no separate React Admin Console folder.
Typical structure:
```
```text
Acme.BookStore/
react/
├── react/ # Your React application
├── dynamic-env.json
│ ├── src/
├── public/
│ │ ├── pages/ # Your page components
│ │ │ ├── books/ # Sample Books CRUD page
│ │ │ └── users/ # Sample Users page
│ │ ├── components/ # Shared UI components
│ │ ├── lib/ # Utilities, API clients
│ │ ├── hooks/ # Custom React hooks
│ │ └── main.tsx # Entry point
│ ├── public/
│ │ └── dynamic-env.json # Runtime configuration
│ ├── package.json
│ └── vite.config.ts
├── src/
├── src/
│ ├── Acme.BookStore.Application/
│ ├── components/
│ ├── Acme.BookStore.Domain/
│ ├── lib/
│ ├── Acme.BookStore.EntityFrameworkCore/
│ ├── locales/
│ └── Acme.BookStore.HttpApi.Host/ # Hosts Admin Console at /admin-console/*
│ ├── pages/
└── ...
│ ├── routes/
```
│ └── main.tsx
├── package.json
### Microservice Template
├── vite.config.ts
└── vitest.config.ts
For `microservice --modern`, both the React app and the React Admin Console are standalone apps under the `apps/` directory, each served through the Web Gateway (YARP).
│ ├── react-admin-console/ # ABP Admin Console (managed by ABP)
│ │ ├── public/
│ │ │ └── dynamic-env.json
│ │ └── ...
│ └── auth-server/ # OpenIddict Auth Server
├── gateways/
│ └── web/ # YARP reverse proxy for React apps
├── services/
│ ├── identity/
│ ├── administration/
│ └── ...
└── ...
```
## Configuration
### Runtime Configuration (`dynamic-env.json`)
The React app reads its runtime configuration from `public/dynamic-env.json`. This file is loaded at startup and allows you to change settings without rebuilding the application, which is useful for different environments like development, staging, and production.
| `oAuthConfig.issuer` | URL of the OpenIddict Auth Server |
| `oAuthConfig.clientId` | The OpenIddict client ID registered for this app |
| `oAuthConfig.scope` | OAuth scopes to request |
| `apis.default.url` | Base URL of the backend API |
| `apis.default.rootNamespace` | Root namespace used for API proxy generation |
For the **microservice** modern template, the `apis.default.url` points to the **Web Gateway** (YARP reverse proxy) instead of a single backend host.
### Admin Console Configuration
For the **microservice** template, the Admin Console has its own `dynamic-env.json` (at `apps/react-admin-console/public/dynamic-env.json`) and uses a separate OpenIddict client (`<ProjectName>_AdminConsole`).
For **layered and single-layer** templates, the Admin Console is embedded in the backend via the `Volo.Abp.AdminConsole` package and does not have a separate configuration file — it inherits its settings from the backend host.
## Authentication
Both the React app and the Admin Console authenticate using **OpenID Connect (OIDC)** against the ABP Auth Server (OpenIddict). The auth flow is handled transparently — when a user visits a protected page, they are redirected to the Auth Server login page and returned to the app after successful authentication. All clients use the **Authorization Code flow with PKCE**, which is the recommended flow for SPAs.
The number of seeded OpenIddict clients depends on the template:
- **Layered and Single-layer templates**: one client is seeded — `<ProjectName>_App` for the React SPA. The Admin Console is embedded in the backend and shares the same authentication context.
- **Microservice template**: two clients are seeded — `<ProjectName>_App` for the main React SPA and `<ProjectName>_AdminConsole` for the standalone React Admin Console app.
## Making API Calls
The React app uses **Axios** as the HTTP client, pre-configured with:
- The base URL from `dynamic-env.json`
- Automatic Bearer token injection from the OIDC session
- ABP-compatible error handling (reads `error.data` from ABP error responses)
**Example: Fetching a list of books**
```typescript
import { useQuery } from '@tanstack/react-query';
import { apiClient } from '@/lib/api-client';
interface BookDto {
id: string;
name: string;
type: number;
publishDate: string;
price: number;
}
interface PagedResult<T> {
items: T[];
totalCount: number;
}
export function useBooks() {
return useQuery({
queryKey: ['books'],
queryFn: () =>
apiClient
.get<PagedResult<BookDto>>('/api/app/book')
.then((res) => res.data),
});
}
```
## Localization
The React app integrates with ABP's [localization system](../../../framework/fundamentals/localization.md). Localization resources are fetched from the backend at startup via the `/api/abp/application-configuration` endpoint and made available throughout the app.
**Example: Using localization in a component**
```typescript
import { useLocalization } from '@/hooks/use-localization';
export function MyComponent() {
const { l } = useLocalization('BookStore');
return <h1>{l('Books')}</h1>;
}
```
The `l(key)` function looks up the key in the loaded localization resources for the given resource name (`'BookStore'` in this example).
## Authorization
Permission checks are available via a hook that reads the current user's granted permissions from the ABP application configuration:
```typescript
import { usePermissions } from '@/hooks/use-permissions';
export function BooksPage() {
const { isGranted } = usePermissions();
return (
<div>
{isGranted('BookStore.Books.Create') && (
<button>Create Book</button>
)}
</div>
);
}
```
```
Permissions are defined on the server side using ABP's [permission system](../../../framework/fundamentals/authorization/index.md) and are automatically available in the React app.
## Creating a Solution
## Tech Stack Details
### shadcn/ui Components
The React app uses [shadcn/ui](https://ui.shadcn.com/) as the component library. shadcn/ui is not a traditional npm package — components are copied directly into your project under `src/components/ui/`, giving you full ownership and the ability to customize them freely.
Common components available out of the box include: `Button`, `Input`, `Table`, `Dialog`, `Form`, `Select`, `Tabs`, `Card`, `Badge`, `Dropdown Menu`, and more.
### Form Validation with Zod
Forms use [Zod](https://zod.dev/) schemas for validation, integrated with [React Hook Form](https://react-hook-form.com/):
```typescript
import { z } from 'zod';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
const createBookSchema = z.object({
Install or update `Volo.Abp.Studio.Cli`, then create a modern solution:
name: z.string().min(1).max(128),
price: z.number().min(0),
publishDate: z.string(),
});
type CreateBookInput = z.infer<typeofcreateBookSchema>;
```bash
# Layered app with React UI
abp new Acme.BookStore --template app --modern --ui-framework react
export function CreateBookForm() {
# Single-layer app with React UI
const form = useForm<CreateBookInput>({
abp new Acme.BookStore --template app-nolayers --modern --ui-framework react
resolver: zodResolver(createBookSchema),
});
// ...
# Microservice solution with React UI
}
abp new Acme.BookStore --template microservice --modern --ui-framework react
```
```
### Testing with Vitest
You can also use ABP Studio v3.0+ and select the modern template flow in the New Solution wizard. The wizard preconfigures local ports, runtime configuration, OIDC clients, theme options, and React/Admin Console wiring based on the selected template and modules.
The React app is pre-configured with [Vitest](https://vitest.dev/) for unit testing:
```bash
# Run tests
npm run test
# Run tests with coverage
npm run test:coverage
```
## Running the Application
## Running the Application
### Development
Start the backend from ABP Studio or by running the backend host projects, then start the React development server.
1. Start the backend (from ABP Studio or `dotnet run` in the `*.HttpApi.Host` project).
2. Navigate to the React app directory and start the dev server.
For **layered and single-layer** templates, the React app is in the `react/` folder at the solution root:
For layered and single-layer templates:
````bash
```bash
cd react
cd react
npm install
npm install
npm run dev
npm run dev
````
```
For the **microservice** template, the React app is under `apps/`:
For microservice templates:
````bash
```bash
cd apps/react
cd apps/react
npm install
npm install
npm run dev
npm run dev
````
```
The app will be available at `https://localhost:3000` (or the port configured in `vite.config.ts`).
3. Access the Admin Console:
- **Layered / Single-layer**: navigate to the backend URL + `/admin-console/` (e.g., `https://localhost:44300/admin-console/`).
- **Microservice**: navigate to the Web Gateway URL + `/admin-console/`.
### Production Build
````bash
# Layered / Single-layer
cd react && npm run build
# Microservice
cd apps/react && npm run build
````
The output is placed in `dist/` and can be served by any static file host or CDN.
## Accessing the Admin Console
The Admin Console is accessible from within the main React app. After logging in, you will find a link to the Admin Console in the navigation. In layered and single-layer solutions it is served by the backend at `/admin-console/*`; in microservice solutions it is served as a standalone React app through the Web Gateway.
The Admin Console provides full management capabilities for:
- **Identity**: Users, Roles, Claims, Organization Units
- **OpenIddict**: Applications, Scopes
- **Settings**: Application-wide and tenant-level settings
- **Audit Logs**: View and filter audit log entries
- **Language Management** *(optional)*
- **Text Template Management** *(optional)*
- **GDPR** *(optional)*
- **SaaS / Tenant Management** *(optional)*
- **And more**, depending on the modules included in your solution
## Customization
### Adding New Pages
Create a new file under `src/pages/` and register the route in the router configuration:
```typescript
Run tests with:
// src/router.tsx (or similar)
import { BooksPage } from './pages/books/books-page';
import { MyNewPage } from './pages/my-feature/my-new-page';
const routes = [
```bash
{ path: '/books', element: <BooksPage/> },
npm run test
{ path: '/my-feature', element: <MyNewPage/> },
// ...
];
```
```
### Adding Menu Items
Build for production with:
Add entries to the navigation configuration to include your new pages in the sidebar or top navigation:
Use these pages to learn each part of the React UI:
Since shadcn/ui components live in `src/components/ui/`, you can modify them directly. For example, to change the default button variant or add a new variant, edit `src/components/ui/button.tsx`.
- [Environment Variables](./environment-variables.md): runtime configuration, `dynamic-env.json`, Vite variables, and Studio-generated defaults.
- [Authorization](./authorization.md): OIDC, Authorization Code flow with PKCE, auth provider, hooks, and route guards.
- [Localization](./localization.md): i18next, local JSON resources, ABP localization keys, and request culture.