Skip to main content

Custom Detail Components

Detail views can be extended with custom Angular or React components using the registerCustomDetailComponent and registerReactCustomDetailComponent functions.

Any components registered in this way will appear below the main detail form.

info

The valid locations for embedding custom detail components can be found in the CustomDetailComponentLocationId docs.

Let's imagine that your project has an external content management system (CMS) which is used to store additional details about products. You might want to display some of this information in the product detail page. We will demonstrate the same component in both Angular and React.

1. Create a component

src/plugins/cms/ui/components/product-info/product-info.component.ts
import { Component, OnInit } from '@angular/core';
import { Observable, switchMap } from 'rxjs';
import { FormGroup } from '@angular/forms';
import { DataService, CustomDetailComponent, SharedModule } from '@vendure/admin-ui/core';
import { CmsDataService } from '../../providers/cms-data.service';

@Component({
template: `
<vdr-card title="CMS Info">
<pre>{{ extraInfo$ | async | json }}</pre>
</vdr-card>`,
standalone: true,
providers: [CmsDataService],
imports: [SharedModule],
})
export class ProductInfoComponent implements CustomDetailComponent, OnInit {
// These two properties are provided by Vendure and will vary
// depending on the particular detail page you are embedding this
// component into. In this case, it will be a "product" entity.
entity$: Observable<any>
detailForm: FormGroup;

extraInfo$: Observable<any>;

constructor(private cmsDataService: CmsDataService) {
}

ngOnInit() {
this.extraInfo$ = this.entity$.pipe(
switchMap(entity => this.cmsDataService.getDataFor(entity.id))
);
}
}

2. Register the component

We can then register the component in our providers.ts file:

src/plugins/cms/ui/providers.ts
import { registerCustomDetailComponent } from '@vendure/admin-ui/core';
import { ProductInfoComponent } from './components/product-info/product-info.component';

export default [
registerCustomDetailComponent({
locationId: 'product-detail',
component: ProductInfoComponent,
}),
];

When running the Admin UI, the component should now appear in the product detail page:

Product detail with custom component

Manipulating the detail form

The detailForm property is an instance of the Angular FormGroup which can be used to manipulate the form fields, set the validity of the form, mark the form as dirty etc. For example, we could add a button which updates the description field of the product:

src/plugins/cms/ui/components/product-info/product-info.component.ts
import { Component, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { CustomDetailComponent } from '@vendure/admin-ui/core';

@Component({
template: `<button class="button secondary" (click)="updateDescription()">Update description</button>`,
standalone: true,
})
export class ProductInfoComponent implements CustomDetailComponent, OnInit {
entity$: Observable<any>
detailForm: FormGroup;

updateDescription() {
const descriptionControl = this.detailForm.get('description');
if (descriptionControl) {
descriptionControl.setValue('New description');
descriptionControl.markAsDirty();
}
}
}