---
title: Implement a Descriptive Text Element
product: Survey Creator
description: Descriptive Text is an element that enables you to create engaging introductions, disclaimers, and add descriptive textual content anywhere within your survey. View our free demo for JavaScript to learn more.
framework: Angular
source: https://surveyjs.io/survey-creator/examples/custom-descriptive-text-element/angular
index: https://surveyjs.io/survey-creator/examples/overview.md
---

# Implement a Descriptive Text Element (Angular)

A Descriptive Text survey element displays a long piece of text. You can use this element to add introductions, disclaimers, or other explanatory texts to your survey. This demo shows how to implement a custom Descriptive Text question type for Survey Creator in Angular and React applications.

A Descriptive Text question type contains the following two custom properties. All other properties are inherited from the `QuestionNonValue` class.

- `caption`: `String`\
A message displayed by the question type.

- `textSize`: `"small"` | `"medium"` | `"large"`\
The size of the text. Text sizes correspond to HTML heading levels as follows:

    | Text size  | Heading |
    | ---------- | ------- |
    | `"large"`  | `<h2>`  |
    | `"medium"` | `<h3>`  |
    | `"small"`  | `<h4>`  |

This demo uses comments in code to guide you through the implementation. If you need more detailed explanations, please refer to help topics about third-party component integration listed below. They cover the same steps because the integration process is very similar to the process of custom question type implementation.

- [Integrate Third-Party Angular Components](/form-library/documentation/customize-question-types/third-party-component-integration-angular)
- [Integrate Third-Party React Components](/form-library/documentation/customize-question-types/third-party-component-integration-react)
- [Integrate Third-Party Vue 3 Components](/form-library/documentation/customize-question-types/third-party-component-integration-vue)

## Files

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

```css
.descriptiveText.small {
    font-size: 0.875rem;
    font-weight: normal;
}

.descriptiveText.medium {
    font-size: 1rem;
    font-weight: bold;
}

.descriptiveText.large {
    font-size: 1.25rem;
    font-weight: bold;
}
```

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

```html
<div style="position: fixed; top: 0; bottom: 0; right: 0; left: 0;">
    <survey-creator [model]="model"></survey-creator>
</div>
```

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

```css
.descriptiveText.small {
    font-size: 0.875rem;
    font-weight: normal;
}

.descriptiveText.medium {
    font-size: 1rem;
    font-weight: bold;
}

.descriptiveText.large {
    font-size: 1.25rem;
    font-weight: bold;
}
```

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

```html
<ng-template #template>
    <span class="descriptiveText" [ngClass]="model.textSize || 'medium'">
        <ng-container *ngTemplateOutlet="elementTitleContent"></ng-container>
    </span>
</ng-template>

<ng-template #elementTitleContent>
    <sv-ng-string [model]="model.locCaption"></sv-ng-string>
</ng-template>
```

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

```ts
import { Component } from "@angular/core";
import { AngularComponentFactory, QuestionAngular } from "survey-angular-ui";
import { ElementFactory, QuestionNonValue, Serializer, settings, surveyLocalization } from "survey-core";
import { getLocaleStrings } from "survey-creator-core";

const CUSTOM_QUESTION_TYPE = "descriptivetext";

// A class that renders a Descriptive Text question
@Component({
    selector: "descriptive-text-component",
    templateUrl: "./descriptive_text.component.html",
    styleUrls: ["./descriptive_text.component.css"]

})
export class DescriptiveTextComponent extends QuestionAngular<DescriptiveTextModel> { }

// Register `DescriptiveTextComponent` as a component that renders the Descriptive Text question type
AngularComponentFactory.Instance.registerComponent(
    CUSTOM_QUESTION_TYPE + "-question",
    DescriptiveTextComponent
);

// A model that extends the Question class and inherits all its properties and methods
export class DescriptiveTextModel extends QuestionNonValue {
    model: { caption: string };

    constructor(name) {
        super(name);
        // Create a `LocalizableString` object for the `caption` property
        this.createLocString({
            name: "caption",
            supportsMarkdown: true,
            translationKey: "descriptiveTextCaption"
        });
    }
    getType() {
        return CUSTOM_QUESTION_TYPE;
    }
    get textSize() {
        return this.getPropertyValue("textSize");
    }
    set textSize(val) {
        this.setPropertyValue("textSize", val);
    }
    // Returns caption text that corresponds to the current locale
    get caption() {
        return this.getLocalizableStringText("caption");
    }
    // Sets caption text for the current locale
    set caption(val) {
        this.setLocalizableStringText("caption", val);
    }
    // Returns a `LocalizationString` object for the `caption` property
    get locCaption() {
        return this.getLocalizableString("caption");
    }
}

// Register `DescriptiveTextModel` as a constructor for the "descriptivetext" question type
ElementFactory.Instance.registerElement(CUSTOM_QUESTION_TYPE, (name) => {
    return new DescriptiveTextModel(name);
});

// Configure JSON serialization and deserialization rules for the custom properties
Serializer.addClass(
    CUSTOM_QUESTION_TYPE,
    [
        {
            name: "caption:text",
            category: "general",
            visibleIndex: 2,
            serializationProperty: "locCaption"
        },
        {
            name: "textSize",
            category: "general",
            visibleIndex: 3,
            default: "medium",
            choices: [
                { value: "small", text: "Small" },
                { value: "medium", text: "Medium" },
                { value: "large", text: "Large" }
            ]
        }
    ],
    function () {
        return new DescriptiveTextModel("");
    },
    "question"
);

// Change default values for inherited properties
Serializer.getProperty(CUSTOM_QUESTION_TYPE, "showNumber").defaultValue = false;
Serializer.getProperty(CUSTOM_QUESTION_TYPE, "titleLocation").defaultValue = "hidden";

// Specify captions to display on the design surface and in Property Grid
const locale = getLocaleStrings("en");
locale.qt[CUSTOM_QUESTION_TYPE] = "Descriptive Text";
locale.pe.caption = "Caption text";
locale.pe.textSize = "Text size";

// Use the Text icon for the Descriptive Text question type
settings.customIcons["icon-descriptivetext"] = "icon-text";

// Specify the default value for the Descriptive Text caption
const enStrings = surveyLocalization.getLocaleStrings("en");
enStrings["descriptiveTextCaption"] = "Default Header Text";
```

### `src/app/components/survey_json.js`

```js
export const surveyJSON = {
  "title": "Customer Feedback Survey",
  "pages": [
    {
      "name": "page1",
      "elements": [
        {
          "type": "descriptivetext",
          "name": "heading",
          "textSize": "large",
          "caption": "This survey is designed to gather feedback from our users. Your responses will help us improve our products and services. Thank you for participating!"
        },
        {
          "type": "radiogroup",
          "name": "satisfaction-level",
          "title": "How satisfied are you with our products?",
          "choices": [
            "Very satisfied",
            "Satisfied",
            "Neutral",
            "Dissatisfied",
            "Very dissatisfied"
          ]
        }
      ]
    }
  ]
}
```

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

```ts
import { Component, OnInit } from "@angular/core";
import { SurveyCreatorModel } from "survey-creator-core";
import "survey-core/survey.i18n";
import "survey-creator-core/survey-creator-core.i18n";
import { surveyJSON } from "./survey_json";

import "survey-core/survey-core.css";
import "survey-creator-core/survey-creator-core.css";

import SurveyTheme from "survey-core/themes";
import { registerCreatorTheme } from "survey-creator-core";

registerCreatorTheme(SurveyTheme); // Add predefined Survey Creator UI themes

@Component({
    // tslint:disable-next-line:component-selector
    selector: "component-survey-creator",
    templateUrl: "./creator.component.html",
    styleUrls: ["./creator.component.css"]
})
export class SurveyCreatorComponent implements OnInit {
    model: SurveyCreatorModel;
    ngOnInit() {
        const creator = new SurveyCreatorModel();
        const propertyStopList = [
            "title",
            "description",
            "isRequired",
            "readOnly",
            "requiredErrorText",
            "validators",
            "useDisplayValuesInDynamicTexts",
            "valueName",
            "clearIfInvisible",
            "defaultValue",
            "correctAnswer",
            "enableIf",
            "defaultValueExpression",
            "requiredIf",
            "descriptionLocation",
            "width",
            "minWidth",
            "maxWidth"
        ];
        // Hide inherited properties that do not apply to the Descriptive Text element
        creator.onPropertyShowing.add((_, options) => {
            if (options.element.getType() === "descriptivetext") {
                options.show = propertyStopList.indexOf(options.property.name) === -1;
            }
        });
        creator.JSON = surveyJSON;
        
        this.model = creator;
    }
}
```

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

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

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

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

@Component({
    selector: "app-root",
    templateUrl: "./app.component.html"
})
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 { SurveyCreatorModule } from "survey-creator-angular";
import { SurveyCreatorComponent } from "./components/creator.component";
import { DescriptiveTextComponent } from "./components/descriptive_text.component";
import { SurveyModule } from "survey-angular-ui";

@NgModule({
    declarations: [AppComponent, SurveyCreatorComponent, DescriptiveTextComponent],
    imports: [BrowserModule, SurveyCreatorModule, 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
<app-root></app-root>
```

### `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
/* You can add global styles to this file and import other style files */
```

### `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-angular-ui": "latest",
    "survey-creator-core": "latest",
    "survey-core": "latest",
    "survey-creator-angular": "latest",
    "tslib": "1.13.0",
    "zone.js": "0.11.7"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~13.0.0",
    "@angular/cli": "~13.0.0",
    "@types/jasmine": "3.6.3",
    "@types/jasminewd2": "2.0.8",
    "@types/node": "14.14.28",
    "codelyzer": "6.0.1",
    "jasmine-core": "3.6.0",
    "jasmine-spec-reporter": "6.0.0",
    "karma": "6.1.1",
    "karma-chrome-launcher": "3.1.0",
    "karma-coverage-istanbul-reporter": "3.0.3",
    "karma-jasmine": "4.0.1",
    "karma-jasmine-html-reporter": "1.5.4",
    "protractor": "7.0.0",
    "ts-node": "9.1.1",
    "tslint": "~6.1.3",
    "typescript": "4.1.5"
  },
  "keywords": [ "angular", "surveyjs" ],
  "description": "SurveyJS-Angular example project"
}
```

## Other Frameworks

- [React](https://surveyjs.io/survey-creator/examples/custom-descriptive-text-element/reactjs.md)
- [Vue 3](https://surveyjs.io/survey-creator/examples/custom-descriptive-text-element/vue3js.md)
- [jQuery](https://surveyjs.io/survey-creator/examples/custom-descriptive-text-element/jquery.md)
- [Vanilla JS](https://surveyjs.io/survey-creator/examples/custom-descriptive-text-element/vanillajs.md)
