PrimeNG Theme Customization — v19 in Angular.

Table of Contents
· Add the OOTB Theme · Customize the OOTB Theme · Component Customization: MegaMenu Component
In this article, we’ll explore how to customize the CSS for a PrimeNG component in an Angular application. If you’re new to PrimeNG, I recommend checking out their installation guide. For those using NX with Angular, you can refer to my earlier article on PrimeNG and Tailwind configuration in an NX Angular app.
Let’s dive into adding and customizing a MegaMenu component for our application. You can learn more about the MegaMenu component in the PrimeNG MegaMenu documentation.
Add the OOTB Theme
Aura, Material, Lara and Nora are the available built-in theme options.
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { appRoutes } from './app.routes';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { providePrimeNG } from 'primeng/config';
import Aura from '@primeng/themes/aura';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(appRoutes),
provideAnimationsAsync(),
providePrimeNG({ theme: { preset: Aura } })
],
};Let’s add a Button and Rating component from PrimeNG to our application and see how they look. This will give us a better idea of the overall theme and styling in action.

Customize the OOTB Theme
The definePreset utility is used to customize an existing preset during the PrimeNG setup. The first parameter is the preset to customize and the second is the design tokens to override.
I have copied the following from here.
//mypreset.ts
import { definePreset } from '@primeng/themes';
import Aura from '@primeng/themes/aura';
const MyPreset = definePreset(Aura, {
semantic: {
primary: {
50: '{zinc.50}',
100: '{zinc.100}',
200: '{zinc.200}',
300: '{zinc.300}',
400: '{zinc.400}',
500: '{zinc.500}',
600: '{zinc.600}',
700: '{zinc.700}',
800: '{zinc.800}',
900: '{zinc.900}',
950: '{zinc.950}'
},
colorScheme: {
light: {
primary: {
color: '{zinc.950}',
inverseColor: '#ffffff',
hoverColor: '{zinc.900}',
activeColor: '{zinc.800}'
},
highlight: {
background: '{zinc.950}',
focusBackground: '{zinc.700}',
color: '#ffffff',
focusColor: '#ffffff'
}
},
dark: {
primary: {
color: '{zinc.50}',
inverseColor: '{zinc.950}',
hoverColor: '{zinc.100}',
activeColor: '{zinc.200}'
},
highlight: {
background: 'rgba(250, 250, 250, .16)',
focusBackground: 'rgba(250, 250, 250, .24)',
color: 'rgba(255,255,255,.87)',
focusColor: 'rgba(255,255,255,.87)'
}
}
}
}
});
export MyPreset;Let’s swap out the zinc color with something more vibrant. I’m going with purple. We’ll replace all instances of zinc with purple. You can find the complete list of available colors here.
const customPreset = definePreset(Aura, {
semantic: {
primary: {
50: '{purple.50}',
100: '{purple.100}',
200: '{purple.200}',
300: '{purple.300}',
400: '{purple.400}',
500: '{purple.500}',
600: '{purple.600}',
700: '{purple.700}',
800: '{purple.800}',
900: '{purple.900}',
950: '{purple.950}',
},
colorScheme: {
light: {
primary: {
color: '{purple.800}',
inverseColor: '#ffffff',
hoverColor: '{purple.900}',
activeColor: '{purple.800}',
},
highlight: {
background: '{purple.950}',
focusBackground: '{purple.700}',
color: '#ffffff',
focusColor: '#ffffff',
},
},
dark: {
primary: {
color: '{purple.50}',
inverseColor: '{purple.950}',
hoverColor: '{purple.100}',
activeColor: '{purple.200}',
},
highlight: {
background: 'rgba(250, 250, 250, .16)',
focusBackground: 'rgba(250, 250, 250, .24)',
color: 'rgba(255,255,255,.87)',
focusColor: 'rgba(255,255,255,.87)',
},
},
},
},
});Use the custom preset instead of the default out-of-the-box (OOTB) in your app.config.ts.
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { appRoutes } from './app.routes';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { providePrimeNG } from 'primeng/config';
import customPreset from './custom.preset';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(appRoutes),
provideAnimationsAsync(),
providePrimeNG({ theme: { preset: customPreset }})
],
};Once the theme override is applied, let’s check how they appear. The changes we made apply to all the components.

Component Customization: MegaMenu Component
We’ll begin by integrating the MegaMenu component into our app. Below is the HTML structure we used for the MegaMenu:
<p-megamenu [model]="items" orientation="vertical" styleClass="p-4">
<ng-template #item let-item>
<a *ngIf="item.root" pRipple class="flex flex-col items-center cursor-pointer px-4 py-2 overflow-hidden relative font-semibold text-lg uppercase" style="border-radius: 2rem">
<i [ngClass]="item.icon" style="font-size: 1.6rem"></i>
<span style="font-size: 11px;">{{ item.label }}</span>
</a>
<a *ngIf="!item.root && !item.image" class="flex items-center p-4 cursor-pointer mb-2 gap-2">
<span class="inline-flex items-center justify-center rounded-full bg-primary text-primary-contrast w-12 h-12">
<i [ngClass]="item.icon + ' text-lg'"></i>
</span>
<span class="inline-flex flex-col gap-1">
<span class="font-medium text-lg text-surface-900 dark:text-surface-0">{{ item.label }}</span>
<span class="whitespace-nowrap">{{ item.subtext }}</span>
</span>
</a>
<div *ngIf="item.image" class="flex flex-col items-start gap-4">
<img [src]="item.image" alt="megamenu-demo" class="w-full" />
<span>{{ item.subtext }}</span>
<p-button [label]="item.label" [outlined]="true"></p-button>
</div>
</ng-template>
</p-megamenu>Here’s the corresponding TypeScript code to define the MegaMenu items:
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MegaMenuItem } from 'primeng/api';
import { MegaMenu } from 'primeng/megamenu';
import { ButtonModule } from 'primeng/button';@Component({
selector: 'app-root',
imports: [MegaMenu, ButtonModule, CommonModule],
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
items: MegaMenuItem[] | undefined; ngOnInit() {
this.items = [
{
label: 'Home',
icon: 'pi pi-home',
root: true,
},
{
label: 'Projects',
icon: 'pi pi-folder',
root: true,
},
{
label: 'Templates',
icon: 'pi pi-database',
root: true,
},
];
}
}This configuration creates a vertical MegaMenu with three root items: Home, Projects, and Templates. Each item includes an icon and label.

How can we modify the color of the icon and label, as well as the background color, when they are focused?

To override the styles of PrimeNG components, using regular CSS in your component won’t work because PrimeNG components are encapsulated in their own styles. You have two options to apply your custom styles:
- You can use the
::ng-deepselector to target styles inside PrimeNG components and override them. - or add the css in the global styles.
Following css will help us acheive above results using ::ng-deep.
:host ::ng-deep {
.p-megamenu-item:not(.p-disabled) > .p-megamenu-item-content:hover{
background-color: #f5f5f5;
color: purple;
}
.p-megamenu-item-content{
color: purple;
}
}
But is there any better way of achieving?
We can use the design tokens of a specific component. However, Overriding components tokens is not the recommended approach if you are building your own style, building your own preset should be preferred instead. This configuration is global and applies to all MegaMenu components, in case you need to customize a particular component on a page locally, view the Scoped CSS section.
import { definePreset } from '@primeng/themes';
import Aura from '@primeng/themes/aura';
const customPreset = definePreset(Aura, {
components: {
megamenu: {
colorScheme: {
light: {
item: {
color: '{purple.700}',
focus: {
background: '{purple.50}',
color: '{purple.700}',
},
},
dark: {
item: {
color: '{purple.700}',
},
},
},
},
},
},
semantic: {
primary: {
50: '{purple.50}',
100: '{purple.100}',
....
},
colorScheme: {
...
},
dark: {
....
},
},
},
});
export default customPreset;You can get the tokens of each component from the component’s documentation. Mega menu’s Design Tokens.






