Getting Started
Writing content
API Documentation
Recipes
API References Develop
Customization Page Processors

Page Processors

Page Processor is a really powerful feature of NgDoc. It allows you to replace HTML elements with Angular components. This is how NgDoc renders different components inside your documentation like demos, playgrounds, icons, etc. Using this API you can create your own components that will make your documentation even more awesome 🎉.

How it works

When NgDoc builder renders your markdown templates to HTML, it leaves special markers in the output HTML. These markers are then replaced by Angular components via Page Processors on the client side. But you can create your own markers by using Markdown or HTML syntax inside your markdown templates, or just use existing HTML elements that you want to improve.

Creating a Page Processor

Page Processor is a simple object that contains CSS selector, component class and function that extracts data from the HTML element and converts it to the component input.

Let's create a simple Page Processor that will replace all <img> elements with ImageViewerComponent, first we need to create the ImageViewerComponent:

image-viewer.component.ts
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { NgDocTooltipDirective } from '@ng-doc/ui-kit';

@Component({
  selector: 'image-viewer',
  standalone: true,
  imports: [NgDocTooltipDirective],
  template: `<img [src]="src" [alt]="alt" [ngDocTooltip]="title" [delay]="0" />`,
  styles: [
    `
      :host {
        display: flex;
        justify-content: center;
        padding: var(--ng-doc-base-gutter);
        border: 1px solid var(--ng-doc-base-2);
        border-radius: var(--ng-doc-base-gutter);
        overflow: hidden;
      }

      img {
        width: 100%;
        max-height: 100px;
        transition: transform 0.2s ease-in-out;
      }

      img:hover {
        transform: scale(1.1);
      }
    `,
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ImageViewerComponent {
  @Input()
  src: string = '';

  @Input()
  alt: string = '';

  @Input()
  title?: string;
}

As you can see, it's a simple component that takes src, alt and title as an inputs, renders the image and adds a simple zoom-in animation on hover with a tooltip that shows the image title.

Now we need to create a Page Processor that will replace all <img> elements with our component:

image.processor.ts
import { NgDocPageProcessor } from '@ng-doc/app/interfaces';

import { ImageViewerComponent } from './image-viewer.component';

export const imageProcessor: NgDocPageProcessor<ImageViewerComponent> = {
  component: ImageViewerComponent,
  selector: 'img',
  extractOptions: (element: Element) => ({
    inputs: {
      src: element.getAttribute('src') || '',
      alt: element.getAttribute('alt') || '',
      title: element.getAttribute('title') || undefined,
    },
  }),
};

Inside the extractOptions method we extract the src, alt and title attributes from the <img> element and define them as inputs for our component.

Now we need to register our Page Processor, you can do it in the ng-doc.page.ts file, if you want to enable it only for one page, or inside your main.ts if you want to enable it for all pages:

Be careful when you register your Page Processors, providePageProcessor function uses multi: true, so if you register your Page Processor in the ng-doc.page.ts file and in the main.ts file, all processors from the main.ts file will be ignored.

ng-doc.page.ts
import { NgDocPage } from '@ng-doc/core';
import { providePageProcessor } from '@ng-doc/app';
import { imageProcessor } from './image.processor';

const MyPage: NgDocPage = {
  title: `MyPage`,
  mdFile: './index.md',
  providers: [providePageProcessor(imageProcessor)],
};

export default MyPage;

After that if you use <img> elements using HTML or Markdown syntax, they will be replaced with the ImageViewerComponent:

index.md
![alt text](assets/images/ng-doc.svg 'Image title')

alt text

Wrapping HTML elements

Sometimes you want to wrap HTML elements with your component, for example, you want to wrap all <table> elements with your custom component that will add some styles to the table. You can do it by playing with nodeToReplace function and content property of the PageProcessor, but first let's create a CustomTableComponent:

custom-table.component.ts
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'custom-table',
  standalone: true,
  template: `<ng-content></ng-content>`,
  styles: [
    `
      custom-table table {
        border: 1px solid red;
      }
    `,
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
})
export class CustomTableComponent {}

Now we need to create a Page Processor that will wrap all <table> elements with our component:

table.processor.ts
import { Injector, Renderer2 } from '@angular/core';
import { NgDocPageProcessor } from '@ng-doc/app/interfaces';

import { CustomTableComponent } from './custom-table.component';

export const tableProcessor: NgDocPageProcessor<CustomTableComponent> = {
  component: CustomTableComponent,
  selector: 'table',
  nodeToReplace: (element: Element, injector: Injector) => {
    // Get the renderer from the injector
    const renderer: Renderer2 = injector.get(Renderer2);
    // Create an anchor element to insert the `CustomTableComponent` in the correct place.
    const anchor: Element = renderer.createElement('div');

    // Insert the anchor before the table and return it
    return element.parentNode?.insertBefore(anchor, element) ?? element;
  },
  extractOptions: (element: Element) => ({
    // Provide the table element as the `ng-content` of the component.
    content: [[element]],
  }),
};

After that when you register your processor all <table> elements will be wrapped with our CustomTableComponent:

index.md
| Syntax    | Description |
| --------- | ----------- |
| Header    | Title       |
| Paragraph | Text        |
SyntaxDescription
HeaderTitle
ParagraphText