---
title: Apply a Theme to a PDF Form
product: PDF Generator
description: Learn how to apply predefined SurveyJS themes to both a web form and its generated PDF version. Switch themes at runtime and see the selected theme applied immediately to the web form and automatically reused in the generated PDF.
framework: Angular
source: https://surveyjs.io/pdf-generator/examples/apply-surveyjs-theme-to-pdf-form/angular
index: https://surveyjs.io/pdf-generator/examples/overview.md
---

# Apply a Theme to a PDF Form (Angular)

This demo shows how predefined SurveyJS themes can be applied to both a web form and its PDF version to maintain a consistent appearance. SurveyJS themes are based on CSS variables and can be shared across all SurveyJS components. By default, the demo uses the Monochrome Light theme, which is optimized for printing. To try other themes or color palettes, open the **Settings** panel using the button in the bottom-right corner.

## Predefined Themes

SurveyJS includes the following [predefined themes](/documentation/themes-and-custom-styles):

- Default
- Contrast
- Borderless
- Flat
- Plain
- 3D
- Soft
- Monochrome

Each theme is available in Light and Dark variations, providing a total of 16 predefined theme options that can be applied to PDF forms.

> SurveyJS themes also include "panelless" variations that remove question containers. These variations are not supported by PDF Generator.

In this and other PDF Generator demos, you can switch themes at runtime using the **Themes** panel. Theme changes are applied to the current web form immediately and used for the generated PDF when you click **Download PDF** or **Preview PDF**. If the **Themes** panel is not visible, open it using the button in the bottom-right corner of the Demo tab.

> In PDF Generator, themes control colors and shadows only. Other visual properties, such as spacing, sizing, typography, and border radius, are defined by [layouts](/pdf-generator/examples/compact-vs-spacious-pdf-layout/).

## Apply a Theme

A SurveyJS theme is a JSON object that defines a form's visual appearance. To apply a theme to a PDF form, import the theme object and pass it to the [`applyTheme`](/pdf-generator/documentation/api-reference/surveypdf#applyTheme) method. The following code applies the Monochrome Light theme:

```js
// Modular applications
import { MonochromeLight } from "survey-core/themes";
import { SurveyPDF } from "survey-pdf";

const surveyJson = { /* Survey JSON schema */ };
const surveyPDF = new SurveyPDF(surveyJson);

surveyPDF.applyTheme(MonochromeLight);

surveyPDF.save("my-pdf-form.pdf");
```

```html
<!-- Classic script applications -->
<head>
  <!-- ... -->
  <script src="https://unpkg.com/survey-core/themes/monochrome-light.min.js"></script>
  <!-- ... -->
</head>
<body>
  <script>
    const surveyPdf = new SurveyPDF.SurveyPDF({ /* ... */});

    surveyPdf.applyLayout(SurveyTheme.MonochromeLight);

    surveyPdf.save("my-monochrome-form.pdf");
  </script>
</body>
```

## Synchronize Themes Between Web and PDF Forms

If users can change themes at runtime, apply the survey's current theme to the PDF form before generating it:

```js
function createSurveyPdfModel(surveyModel) {
  const surveyPDF = new SurveyPDF(surveyJson, pdfOptions);

  if (surveyModel) {
    surveyPDF.data = surveyModel.data;
    surveyPDF.locale = surveyModel.locale;
    
    if (surveyModel.theme) {
      surveyPDF.applyTheme(surveyModel.theme);
    }
  }

  return surveyPDF;
}
```

For more information about themes and other appearance customization options, refer to the following help topic:

[PDF Appearance Customization](/pdf-generator/documentation/pdf-appearance-customization (linkStyle))

## Files

### `src/app/components/json.ts`

```ts
export const json = {
  "title": "Product Feedback",
  "description": "Share your experience with our platform. Required fields are marked with *.",
  "pages": [
    {
      "name": "feedback",
      "elements": [
        {
          "type": "panel",
          "name": "profile",
          "title": "Your profile",
          "elements": [
            {
              "type": "text",
              "name": "full-name",
              "title": "Full name",
              "isRequired": true
            },
            {
              "type": "text",
              "name": "email",
              "startWithNewLine": false,
              "title": "Work email",
              "isRequired": true,
              "inputType": "email",
              "validators": [{ "type": "email" }]
            },
            {
              "type": "dropdown",
              "name": "role",
              "title": "Your role",
              "choices": [
                "Developer",
                "Product manager",
                "Designer",
                "QA engineer",
                "Other"
              ]
            }
          ]
        },
        {
          "type": "matrix",
          "name": "feature-ratings",
          "title": "How would you rate the following?",
          "description": "Rate each area from 1 (poor) to 5 (excellent).",
          "rowTitleWidth": "140px",
          "columns": [1, 2, 3, 4, 5],
          "rows": [
            { "value": "ui", "text": "User interface" },
            { "value": "performance", "text": "Performance" },
            { "value": "docs", "text": "Documentation" },
            { "value": "api", "text": "API & integrations" },
            { "value": "support", "text": "Support quality" }
          ],
          "eachRowRequired": true
        },
        {
          "type": "rating",
          "name": "overall",
          "title": "Overall satisfaction",
          "rateCount": 5,
          "rateMin": 1,
          "rateMax": 5,
          "minRateDescription": "Very dissatisfied",
          "maxRateDescription": "Very satisfied"
        },
        {
          "type": "checkbox",
          "name": "used-features",
          "title": "Which features do you use regularly?",
          "choices": [
            "Form builder",
            "PDF export",
            "Analytics dashboard",
            "Custom themes",
            "Team collaboration"
          ],
          "colCount": 2,
          "showOtherItem": true,
          "otherText": "Other"
        },
        {
          "type": "comment",
          "name": "improvements",
          "title": "What should we improve next?",
          "maxLength": 500
        },
        {
          "type": "boolean",
          "name": "recommend",
          "title": "Would you recommend us to a colleague?",
          "valueTrue": "yes",
          "valueFalse": "no"
        }
      ]
    }
  ],
  "showQuestionNumbers": false,
  "headerView": "advanced"
}
;
```

### `src/app/components/pdf.component.css`

```css
/* You can add your custom CSS here. */
```

### `src/app/components/pdf.component.html`

```html
<survey [model]="model"></survey>
```

### `src/app/components/pdf.component.ts`

```ts
import { Component, OnInit } from "@angular/core";
import { Model } from "survey-core";
import { SurveyPDF } from "survey-pdf";
import { json } from "./json";
import SurveyTheme from "survey-core/themes";
import "./pdf.component.css";
import "survey-core/survey-core.min.css";

function createSurveyPdfModel (surveyModel) {
    const surveyPDF = new SurveyPDF(json);
    if (surveyModel) {
        surveyPDF.data = surveyModel.data;
        surveyPDF.locale = surveyModel.locale;
        surveyPDF.applyTheme(SurveyTheme.MonochromeLight);
        
    }
    surveyPDF.onGetQuestionStyle.add((_, options) => {  
        if (options.question.getType() === "matrix") {
            options.style.columnMinWidth = 20;
        }
    });
    return surveyPDF;
}
function saveSurveyToPdf (filename, surveyModel) {
    const pdfDoc = createSurveyPdfModel(surveyModel);
    if (!pdfDoc) return;

    pdfDoc.save(filename);
}

const previewDiv = document.getElementById("pdf-preview");
const previewEmbed = document.getElementById("pdf-preview-frame");
let pdfBlobUrl;

function showPdfPreview(surveyModel) {
    if (!previewDiv || !previewEmbed) return;

    const pdfDoc = createSurveyPdfModel(surveyModel);
    if (!pdfDoc) return;

    pdfDoc.raw("blob").then((blob) => {
        if (pdfBlobUrl) {
            URL.revokeObjectURL(pdfBlobUrl);
        }
        pdfBlobUrl = URL.createObjectURL(blob);
        previewEmbed.setAttribute("src", pdfBlobUrl);
        previewDiv.style.display = "block";
    });
}

function previewPdf(surveyModel) {
    if (!previewDiv) return;

    if (previewDiv.style.display !== "none") {
        previewDiv.style.display = "none";
        return;
    }

    showPdfPreview(surveyModel);
}

@Component({
    // tslint:disable-next-line:component-selector
    selector: "component-survey",
    templateUrl: "./pdf.component.html",
    styleUrls: ["./pdf.component.css"]
})
export class SurveyPdfComponent implements OnInit {
    model: Model;
    ngOnInit() {
        const survey = new Model(json);
        survey.applyTheme(SurveyTheme.MonochromeLight);
        survey.showCompleteButton = false;
        survey.navigationButtonsLocation = "topBottom";
        survey.addNavigationItem({
            id: "survey_save_as_file",
            title: "Download PDF",
            action: () => {
                saveSurveyToPdf("surveyResult.pdf", survey);
            }
        });
        survey.addNavigationItem({
            id: "survey_pdf_preview",
            title: "Preview PDF",
            visible: window.navigator.pdfViewerEnabled,
            action: () => {
                previewPdf(survey);
            }
        });
        this.model = survey;
    }
}
```

### `src/app/components/theme.ts`

```ts
export const themeJson = {};
```

### `src/app/app.component.css`

```css

```

### `src/app/app.component.html`

```html
<component-survey></component-survey>
```

### `src/app/app.component.ts`

```ts
import { Component } from "@angular/core";

@Component({
    selector: "app-root",
    templateUrl: "./app.component.html",
    styleUrls: ["./app.component.css"]
})
export class AppComponent {
    title = "CodeSandbox";
}
```

### `src/app/app.module.ts`

```ts
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

import { AppComponent } from "./app.component";
import { SurveyModule } from "survey-angular-ui";
import { SurveyPdfComponent } from "./components/pdf.component";

@NgModule({
    declarations: [AppComponent, SurveyPdfComponent],
    imports: [BrowserModule, SurveyModule],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
```

### `src/environments/environment.prod.ts`

```ts
export const environment = {
    production: true
};
```

### `src/environments/environment.ts`

```ts
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.

export const environment = {
    production: false
};
```

### `src/index.html`

```html
<div style="display: flex;">
    <div id="surveyElement" style="flex: 1 1 0%; height: 100%; min-width: 0;">
        <app-root></app-root>
    </div>
    <div id="pdf-preview" style="flex: 0.7 0.7 0%; display: none">
        <embed id="pdf-preview-frame" type="application/pdf" style="width:100%; height:100%;" />
    </div>
</div>
```

### `src/main.ts`

```ts
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

import { AppModule } from "./app/app.module";
import { environment } from "./environments/environment";

if (environment.production) {
    enableProdMode();
}

platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .catch(err => console.log(err));
```

### `src/polyfills.ts`

```ts
/**
 * This file includes polyfills needed by Angular and is loaded before the app.
 * You can add your own extra polyfills to this file.
 *
 * This file is divided into 2 sections:
 *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
 *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
 *      file.
 *
 * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
 * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
 * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
 *
 * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
 */

/***************************************************************************************************
 * BROWSER POLYFILLS
 */

/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';

/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js';  // Run `npm install classlist.js`.

/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';

/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import "core-js/proposals/reflect-metadata";

/**
 * Required to support Web Animations `@angular/platform-browser/animations`.
 * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
 **/
// import 'web-animations-js';  // Run `npm install web-animations-js`.

/***************************************************************************************************
 * Zone JS is required by default for Angular itself.
 */
import "zone.js/dist/zone"; // Included with Angular CLI.

/***************************************************************************************************
 * APPLICATION IMPORTS
 */
```

### `src/styles.css`

```css

```

### `src/typings.d.ts`

```ts
/* SystemJS module definition */
declare var module: NodeModule;
interface NodeModule {
    id: string;
}
```

### `.angular-cli.json`

```json
{
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [ "assets", "favicon.ico" ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "prefix": "app",
      "styles": [ "styles.css" ],
      "scripts": [ ],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ]
}
```

### `_tsconfig.json`

```json
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "allowSyntheticDefaultImports": true,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "resolveJsonModule": true,
    "target": "es2015",
    "module": "es2020",
    "lib": [
      "es2018",
      "dom"
    ]
  }
}
```

### `package.json`

```json
{
  "name": "surveyjs-angular",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "14.1.1",
    "@angular/cdk": "14.1.1",
    "@angular/common": "14.1.1",
    "@angular/compiler": "14.1.1",
    "@angular/core": "14.1.1",
    "@angular/forms": "14.1.1",
    "@angular/platform-browser": "14.1.1",
    "@angular/platform-browser-dynamic": "14.1.1",
    "@angular/router": "14.1.1",
    "core-js": "3.6.4",
    "rxjs": "6.5.4",
    "survey-core": "latest",
    "survey-angular-ui": "latest",
    "survey-pdf": "latest",
    "tslib": "1.13.0",
    "zone.js": "0.11.7"
  },
  "devDependencies": {
    "@angular/cli": "1.6.6",
    "@angular/compiler-cli": "^5.2.0",
    "@angular/language-service": "^5.2.0",
    "@types/core-js": "0.9.46",
    "@types/jasmine": "~2.8.3",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "^4.0.1",
    "jasmine-core": "~2.8.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~2.0.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~4.1.0",
    "tslint": "~5.9.1",
    "typescript": "3.9.7"
  },
  "keywords": [ "angular", "surveyjs" ],
  "description": "SurveyJS-Angular example project"
}
```

## Other Frameworks

- [React](https://surveyjs.io/pdf-generator/examples/apply-surveyjs-theme-to-pdf-form/reactjs.md)
- [Vue 3](https://surveyjs.io/pdf-generator/examples/apply-surveyjs-theme-to-pdf-form/vue3js.md)
- [jQuery](https://surveyjs.io/pdf-generator/examples/apply-surveyjs-theme-to-pdf-form/jquery.md)
- [Vanilla JS](https://surveyjs.io/pdf-generator/examples/apply-surveyjs-theme-to-pdf-form/vanillajs.md)
