All Components

Multi-Page Content

The PDF Export enables you to generate multi-page content in PDF.

To export a multi-page file in PDF, either:

Manual Setting of Page Breaks

To manually specify the page breaks, set the forcePageBreak property. As a result, a page break, which matches the forcePageBreak CSS selector, occurs before each element.

import { Component } from '@angular/core';

/* tslint:disable:max-line-length */
@Component({
  selector: 'my-app',
  template: `
    <div class="example-config">
      <button kendo-button (click)="pdf.saveAs('manual-paging.pdf')">
        Save As PDF...
      </button>
    </div>

    <kendo-pdf-export #pdf forcePageBreak=".page-break">
      <div class="size-a4">
        <h3>Page 1</h3>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer felis libero, lobortis ac rutrum quis, varius a velit. Donec lacus erat, cursus sed porta quis, adipiscing et ligula. Duis volutpat, sem pharetra accumsan pharetra, mi ligula cursus felis, ac aliquet leo diam eget risus. Integer facilisis, justo cursus venenatis vehicula, massa nisl tempor sem, in ullamcorper neque mauris in orci.
        </p>
        <p>
            Ut orci ligula, varius ac consequat in, rhoncus in dolor. Mauris pulvinar molestie accumsan. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean velit ligula, pharetra quis aliquam sed, scelerisque sed sapien. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam dui mi, vulputate vitae pulvinar ac, condimentum sed eros.
        </p>

        <h3 class='page-break'>Page 2</h3>
        <p>
            Aliquam at nisl quis est adipiscing bibendum. Nam malesuada eros facilisis arcu vulputate at aliquam nunc tempor. In commodo scelerisque enim, eget sodales lorem condimentum rutrum. Phasellus sem metus, ultricies at commodo in, tristique non est. Morbi vel mauris eget mauris commodo elementum. Nam eget libero lacus, ut sollicitudin ante. Nam odio quam, suscipit a fringilla eget, dignissim nec arcu. Donec tristique arcu ut sapien elementum pellentesque.
        </p>
        <p>
            Maecenas vitae eros vel enim molestie cursus. Proin ut lacinia ipsum. Nam at elit arcu, at porttitor ipsum. Praesent id viverra lorem. Nam lacinia elementum fermentum. Nulla facilisi. Nulla bibendum erat sed sem interdum suscipit. Vestibulum eget molestie leo. Aliquam erat volutpat. Ut sed nulla libero. Suspendisse id euismod quam. Aliquam interdum turpis vitae purus consectetur in pulvinar libero accumsan. In id augue dui, ac volutpat ante. Suspendisse purus est, ullamcorper id bibendum sed, placerat id leo.
        </p>
      </div>
    </kendo-pdf-export>
  `,
  styles: [`
    /*
      For details see:
      http://www.telerik.com/kendo-angular-ui/components/drawing/drawing-dom/#toc-dimensions-and-css-units
    */
    .size-a4 { width: 595px; height: 841px; }

    kendo-pdf-export {
      font-family: "DejaVu Sans", "Arial", sans-serif;
      font-size: 12px;
    }
  `]
})
export class AppComponent {
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule } from '@angular/forms';
import { PDFExportModule } from '@progress/kendo-angular-pdf-export';
import { IntlModule } from '@progress/kendo-angular-intl';
import { NumericTextBoxModule } from '@progress/kendo-angular-inputs';
import { ButtonsModule } from '@progress/kendo-angular-buttons';

import { AppComponent } from './app.component';

@NgModule({
  imports:      [
    BrowserModule,
    BrowserAnimationsModule,
    ButtonsModule,
    IntlModule,
    FormsModule,
    NumericTextBoxModule,
    PDFExportModule
  ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

import { enableProdMode, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Automatic Page Splitting

The PDF Export component supports automatic page breaking.

Overview

To automatically implement the page breaks, set the paperSize PDF option. You will still be able to apply the forcePageBreak configuration to manually specify the break points.

import { Component } from '@angular/core';

/* tslint:disable:max-line-length */
@Component({
  selector: 'my-app',
  template: `
    <div class="example-config">
      <button kendo-button (click)="pdf.saveAs('auto-paging.pdf')">
        Save As PDF...
      </button>
    </div>

    <kendo-pdf-export #pdf paperSize="A4" margin="2cm">
        <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer felis libero, lobortis ac rutrum quis, varius a velit. Donec lacus erat, cursus sed porta quis, adipiscing et ligula. Duis volutpat, sem pharetra accumsan pharetra, mi ligula cursus felis, ac aliquet leo diam eget risus. Integer facilisis, justo cursus venenatis vehicula, massa nisl tempor sem, in ullamcorper neque mauris in orci.
        </p>
        <p>
            Ut orci ligula, varius ac consequat in, rhoncus in dolor. Mauris pulvinar molestie accumsan. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean velit ligula, pharetra quis aliquam sed, scelerisque sed sapien. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam dui mi, vulputate vitae pulvinar ac, condimentum sed eros.
        </p>
        <p>
            Aliquam at nisl quis est adipiscing bibendum. Nam malesuada eros facilisis arcu vulputate at aliquam nunc tempor. In commodo scelerisque enim, eget sodales lorem condimentum rutrum. Phasellus sem metus, ultricies at commodo in, tristique non est. Morbi vel mauris eget mauris commodo elementum. Nam eget libero lacus, ut sollicitudin ante. Nam odio quam, suscipit a fringilla eget, dignissim nec arcu. Donec tristique arcu ut sapien elementum pellentesque.
        </p>
        <p>
            Maecenas vitae eros vel enim molestie cursus. Proin ut lacinia ipsum. Nam at elit arcu, at porttitor ipsum. Praesent id viverra lorem. Nam lacinia elementum fermentum. Nulla facilisi. Nulla bibendum erat sed sem interdum suscipit. Vestibulum eget molestie leo. Aliquam erat volutpat. Ut sed nulla libero. Suspendisse id euismod quam. Aliquam interdum turpis vitae purus consectetur in pulvinar libero accumsan. In id augue dui, ac volutpat ante. Suspendisse purus est, ullamcorper id bibendum sed, placerat id leo.
        </p>
    </kendo-pdf-export>
  `,
  styles: [ `
    p { font-size: 21px; };
    kendo-pdf-export {
      font-family: "DejaVu Sans", "Arial", sans-serif;
      font-size: 12px;
    }
  `]
})
export class AppComponent {
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule } from '@angular/forms';
import { PDFExportModule } from '@progress/kendo-angular-pdf-export';
import { IntlModule } from '@progress/kendo-angular-intl';
import { NumericTextBoxModule } from '@progress/kendo-angular-inputs';
import { ButtonsModule } from '@progress/kendo-angular-buttons';

import { AppComponent } from './app.component';

@NgModule({
  imports:      [
    BrowserModule,
    BrowserAnimationsModule,
    ButtonsModule,
    IntlModule,
    FormsModule,
    NumericTextBoxModule,
    PDFExportModule
  ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

import { enableProdMode, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Page Templates

When you request a multi-page output through the forcePageBreak or paperSize options, you can additionally specify a page template. This template is inserted into each page before the output is produced and you can position it relatively to the page by using CSS. The template has to be a function which receives the number of the current page (pageNum) and the total number of pages (totalPages).

import { Component } from '@angular/core';
import { InvoiceRow } from './invoice-row';
import { invoiceData } from './invoice-data';

@Component({
  selector: 'my-app',
  template: `
    <div class="example-config">
      <button kendo-button (click)="pdf.saveAs('page-template.pdf')">
        Save As PDF...
      </button>
    </div>

    <kendo-pdf-export #pdf paperSize="A4" margin="2cm">
      <ng-template kendoPDFTemplate let-pageNum="pageNum" let-totalPages="totalPages">
        <div class="pageNum">
          Page {{ pageNum }} of {{ totalPages }}
        </div>
      </ng-template>
      <my-invoice [data]="data"></my-invoice>
    </kendo-pdf-export>
  `,
  styles: [`
    .pageNum {
      font-family: "DejaVu Sans", "Arial", sans-serif;
      position: absolute;
      top: 10px;
      left: 10px;
    }

    kendo-pdf-export {
      font-family: "DejaVu Sans", "Arial", sans-serif;
      font-size: 12px;
    }
  `]
})
export class AppComponent {
  public data: InvoiceRow[] = [...invoiceData, ...invoiceData, ...invoiceData];
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { PDFExportModule } from '@progress/kendo-angular-pdf-export';
import { IntlModule } from '@progress/kendo-angular-intl';
import { GridModule } from '@progress/kendo-angular-grid';

import { AppComponent } from './app.component';
import { InvoiceComponent } from './invoice.component';

@NgModule({
  imports:      [
    BrowserModule,
    BrowserAnimationsModule,
    IntlModule,
    GridModule,
    PDFExportModule
  ],
  declarations: [ AppComponent, InvoiceComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

import { Component, Input } from '@angular/core';
import { aggregateBy } from '@progress/kendo-data-query';
import { InvoiceRow } from './invoice-row';

@Component({
  selector: 'my-invoice',
  template: `
    <div class="header">
        Blauer See Delikatessen
    </div>

    <div class="address">
      <div class="for">
        <h3>Invoice For</h3>
        <p>
          Antonio Moreno<br /> Naucalpan de Juárez<br /> México D.F., Mexico, 53500
        </p>
      </div>

      <div class="from">
        <h3>From</h3>
        <p>
          Hanna Moos <br /> Lützowplatz 456<br /> Berlin, Germany, 10785
        </p>
      </div>
    </div>

    <div class="items">
      <kendo-grid [data]="data" scrollable="none">
        <kendo-grid-column field="productName" title="Product">
          <ng-template kendoGridFooterTemplate>
            Total
          </ng-template>
        </kendo-grid-column>
        <kendo-grid-column field="unitPrice" format="{0:c}" title="Price" width="120"
                            [style]="rightAlign" [footerStyle]="rightAlign">
        </kendo-grid-column>
        <kendo-grid-column field="qty" title="Pcs." width="120"
                            [style]="rightAlign" [footerStyle]="rightAlign">
          <ng-template kendoGridFooterTemplate let-column="column">
            {{ totals[column.field].sum }}
          </ng-template>
        </kendo-grid-column>
        <kendo-grid-column field="total" format="{0:c}" title="Total" width="120"
                            [style]="rightAlign" [footerStyle]="rightAlign">
          <ng-template kendoGridFooterTemplate let-column="column">
            {{ totals[column.field].sum | kendoNumber:'c' }}
          </ng-template>
        </kendo-grid-column>
      </kendo-grid>
    </div>

    <div class="signature">
      Signature: ________________
    </div>
  `,
  styles: [`
    .header {
      font-size: 30px;
      font-weight: bold;
      margin: 0 0 20px 0;
      border-bottom: 1px solid #e5e5e5;
      color: #3aabf0;
    }

    .address {
        display: flex;
        justify-content: space-between;
        margin: 0 0 20px 0;
    }

    .from p, .for p {
      color: #787878;
    }

    .signature {
      padding-top: 36px;
    }
  `]
})
export class InvoiceComponent {
  @Input()
  public data: InvoiceRow[] = [];

  private aggregates: any[] = [{
    field: 'qty', aggregate: 'sum'
  }, {
    field: 'total', aggregate: 'sum'
  }];

  public get totals(): any {
    return aggregateBy(this.data, this.aggregates) || {};
  }
}
import { InvoiceRow } from './invoice-row';

export const invoiceData = [
  new InvoiceRow('QUESO CABRALES', 21, 5),
  new InvoiceRow('ALICE MUTTON', 39, 7),
  new InvoiceRow('GENEN SHOUYU', 15.50, 3),
  new InvoiceRow('CHARTREUSE VERTE', 18, 1),
  new InvoiceRow('MASCARPONE FABIOLI', 32, 2),
  new InvoiceRow('VALKOINEN SUKLAA', 16.25, 3)
];

export class InvoiceRow {
  public get total(): number {
    return this.unitPrice * this.qty;
  }

  constructor(
    public productName: string,
    public unitPrice: number,
    public qty: number
  ) {}
}
import { enableProdMode, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Preventing Page Breaks in Elements

To prevent elements from being split across pages, use the keepTogether option. The option has to be a CSS selector that is passable to querySelector.

In the following example, all elements from the previous example which have the 'prevent-split' CSS class are kept within the boundaries of the pages and their content is not split. If they fall on a margin, they will be moved to the next page.

import { Component } from '@angular/core';

/* tslint:disable:max-line-length */
@Component({
  selector: 'my-app',
  template: `
    <div class="example-config">
      <p>
        <input id="breakParagraphs" type="checkbox" [(ngModel)]="breakParagraphs"/>
        <label for="breakParagraphs">Break paragraphs</label>
      </p>
      <button kendo-button (click)="pdf.saveAs('keep-together.pdf')">
        Save As PDF...
      </button>
    </div>

    <kendo-pdf-export #pdf paperSize="A4" margin="2cm" [keepTogether]="keepTogether">
        <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer felis libero, lobortis ac rutrum quis, varius a velit. Donec lacus erat, cursus sed porta quis, adipiscing et ligula. Duis volutpat, sem pharetra accumsan pharetra, mi ligula cursus felis, ac aliquet leo diam eget risus. Integer facilisis, justo cursus venenatis vehicula, massa nisl tempor sem, in ullamcorper neque mauris in orci.
        </p>
        <p>
            Ut orci ligula, varius ac consequat in, rhoncus in dolor. Mauris pulvinar molestie accumsan. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean velit ligula, pharetra quis aliquam sed, scelerisque sed sapien. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam dui mi, vulputate vitae pulvinar ac, condimentum sed eros.
        </p>
        <p>
            Aliquam at nisl quis est adipiscing bibendum. Nam malesuada eros facilisis arcu vulputate at aliquam nunc tempor. In commodo scelerisque enim, eget sodales lorem condimentum rutrum. Phasellus sem metus, ultricies at commodo in, tristique non est. Morbi vel mauris eget mauris commodo elementum. Nam eget libero lacus, ut sollicitudin ante. Nam odio quam, suscipit a fringilla eget, dignissim nec arcu. Donec tristique arcu ut sapien elementum pellentesque.
        </p>
        <p>
            Maecenas vitae eros vel enim molestie cursus. Proin ut lacinia ipsum. Nam at elit arcu, at porttitor ipsum. Praesent id viverra lorem. Nam lacinia elementum fermentum. Nulla facilisi. Nulla bibendum erat sed sem interdum suscipit. Vestibulum eget molestie leo. Aliquam erat volutpat. Ut sed nulla libero. Suspendisse id euismod quam. Aliquam interdum turpis vitae purus consectetur in pulvinar libero accumsan. In id augue dui, ac volutpat ante. Suspendisse purus est, ullamcorper id bibendum sed, placerat id leo.
        </p>
    </kendo-pdf-export>
  `,
  styles: [`
    p {
      font-size: 18px;
    }

    kendo-pdf-export {
      font-family: "DejaVu Sans", "Arial", sans-serif;
      font-size: 12px;
    }
  `]
})
export class AppComponent {
  public breakParagraphs = false;

  public get keepTogether(): string {
    return this.breakParagraphs ? '' : 'p';
  }
}

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule } from '@angular/forms';
import { PDFExportModule } from '@progress/kendo-angular-pdf-export';
import { IntlModule } from '@progress/kendo-angular-intl';
import { NumericTextBoxModule } from '@progress/kendo-angular-inputs';
import { ButtonsModule } from '@progress/kendo-angular-buttons';

import { AppComponent } from './app.component';

@NgModule({
  imports:      [
    BrowserModule,
    BrowserAnimationsModule,
    ButtonsModule,
    IntlModule,
    FormsModule,
    NumericTextBoxModule,
    PDFExportModule
  ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

import { enableProdMode, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Known Limitations

  • If an element does not have textual content, it will not be split across pages. For example, a <div> element which contains text will be split. A <div> element which does not contain text but includes a border or a background image will not be split. If an element that is not subject to splitting falls on a page boundary, it will be moved to the next page along with all DOM nodes that follow it. If the element does not fit in a single page, it will be truncated.

    The following elements will not be split across pages:

    • <img>
    • <tr>
    • <iframe>
    • <svg>
    • <object>
    • <canvas>
    • <input>
    • <textarea>
    • <select>
    • <video>
  • Positioned elements (position: absolute) do not support automatic page breaking. For example, the input on an A4 page, which is demonstrated in the following example, will only display the Foo and the Baz paragraphs in the output file and the positioned <div> element will appear on the first page at height 1000. Because this dimension is beyond the page boundary, the content will be clipped.

    <p>Foo</p>
    <div style="position: absolute; top: 1000px">Bar</div>
    <p>Baz</p>
  • If the algorithm moves a node to the next page and even if the space to position it on the current page might be sufficient, all DOM nodes which follow that node will be moved as well.

    The following example demonstrates a floating element which might end up in a position where the whole text fits on the current page but the image is higher and falls on the boundary. In this case, the image and a part of the text that follows it will be moved to the next page.

    <p>
     some text before
     <img style="float: left" ... />
     some text after
    </p>
In this article