---
title: "Content filtering options"
description: "Configure content filtering and sanitization using valid_elements, invalid_elements, extended_valid_elements, and paste hooks. Control which HTML elements and attributes TinyMCE allows or removes when content is inserted or pasted."
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/content-filtering/"
md_url: "https://www.tiny.cloud/docs/tinymce/latest/content-filtering/index.md"
version: "latest"
last_updated: "2026-09-28T22:41:52Z"
tokens: 11301
---
# Content filtering options

Use `valid_elements` to define which elements and attributes are allowed, `invalid_elements` to block specific elements, and `extended_valid_elements` to add or modify rules. For paste-time filtering, use the `PastePreProcess` and `PastePostProcess` events or the [PowerPaste](../introduction-to-powerpaste/) plugin options.

## Disabling or stripping HTML formatting

TinyMCE validates and cleans content against a schema whenever content is set, pasted, or retrieved. The schema defines which elements and attributes are allowed, and any element or attribute outside the schema is removed when the content is parsed. The content filtering options on this page configure that schema:

- [`valid_elements`](#valid_elements) replaces the set of allowed elements and attributes.
- [`extended_valid_elements`](#extended_valid_elements) adds to the existing set rather than replacing it.
- [`invalid_elements`](#invalid_elements) removes specific elements from the content, keeping their text.

Of these options, only [`valid_elements`](#valid_elements) and [`invalid_elements`](#invalid_elements) restrict content. [`extended_valid_elements`](#extended_valid_elements) widens the default schema, so it is used to permit additional elements rather than to strip them. For its syntax and examples, see the option description below.

For a reference of the underlying validation and parsing mechanism, see the [Schema](../apis/tinymce.html.schema/) and [DomParser](../apis/tinymce.html.domparser/) API documentation.

To restrict content to a limited subset of formatting, set [`valid_elements`](#valid_elements) to only the elements and attributes that should be kept. Any element outside the list is removed and its text content is preserved.

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  valid_elements: 'p,br,a[href],strong/b,em/i'
});
```
This configuration keeps paragraphs, line breaks, links (with their `href` attribute), and bold and italic text, converting `b` to `strong` and `i` to `em`. All other elements, such as headings, tables, and inline styles, are stripped and their text is retained.

When a stripped element is a block element, such as a heading, the text it contained is left without a parent block and is rewrapped in the block element set by [`forced_root_block`](#forced_root_block), which is `p` by default. For example, an `<h1>` removed by the configuration above is returned as a `<p>` containing the original heading text.

To remove only specific formatting while keeping everything else, use [`invalid_elements`](#invalid_elements).

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  invalid_elements: 'strong,b,em,i,u,span'
});
```
To remove all formatting from pasted content so that only plain text is inserted, set [paste_as_text](../copy-and-paste/#paste_as_text) to `true`.

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  paste_as_text: true
});
```
For a complete reference of the element and attribute syntax used by [`valid_elements`](#valid_elements), [`extended_valid_elements`](#extended_valid_elements), and [`invalid_elements`](#invalid_elements), see the option descriptions below. To customize how content is styled and defined rather than restricted, see [Content formats](../content-formatting/).

## `allow_conditional_comments`

This option allows you to specify whether the editor should parse and keep conditional comments.

**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

### Example: using `allow_conditional_comments`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  allow_conditional_comments: true
});
```

## `allow_html_in_comments`

The `allow_html_in_comments` option allows HTML-like content to be retained in comments within the editor content. By default, TinyMCE removes comments containing HTML-like content as a security measure.

**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

> **Warning:** Setting this option to `true` may expose your application to XSS vulnerabilities. The DOMPurify maintainers have identified potential security risks when HTML-like content is allowed in comments. Only enable this option if you trust your content sources and understand the security implications.

### Example: using `allow_html_in_comments`

The following example demonstrates how comments containing HTML are handled by default (removed) and how to configure TinyMCE to retain them:

```js
tinymce.init({
  selector: 'textarea',
  allow_html_in_comments: true,  // Enable HTML in comments
});
```

### Comment behavior examples

With `allow_html_in_comments: false` (default), the editor’s content after initialization will be:

```html
<section>
<h1>Some content</h1>
<h1>Some additional content</h1>
</section>
```
With `allow_html_in_comments: true`, the editor’s content after initialization will be:

```html
<section>
<h1>Some content</h1>
<!--
  <div>This is my comment content</div>
-->
<h1>Some additional content</h1>
</section>
```

## `allow_html_in_named_anchor`

This option allows you to specify whether the editor should parse and keep `html` within named `anchor` tags.

**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

### Example: using `allow_html_in_named_anchor`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  allow_html_in_named_anchor: true
});
```

## `allow_mathml_annotation_encodings`

This option allows a specific list of valid MathML annotation encodings to be used in the editor.

**Type:** `Array` of `Strings`

**Default value:** `[]` (empty array)

### Example: using `allow_mathml_annotation_encodings`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  allow_mathml_annotation_encodings: [ 'wiris', 'application/x-tex' ]
});
```

## `allow_unsafe_link_target`

By default all links with a `target` of *_blank* will get a `rel` attribute of `noopener`. This will disable access to the `window.opener` object from a child tab/window that will open on click. If this is not something you care about, you can disable this option, by setting it to *false*. Although **we do not recommend** you to do so unless you have other ways of securing links to external pages using target set to *_blank*.

**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

### Example: using `allow_unsafe_link_target`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  allow_unsafe_link_target: true
});
```

## `br_in_pre`

This option allows you to disable TinyMCE’s default behavior when pressing the enter key within a `pre` tag. By default, pressing enter within a `pre` tag produces a `br` tag at the insertion point. For example:

`<pre>This is inside<br>a pre tag.</pre>`

However, when `br_in_pre` is set to `false`, rather than inserting a `br` tag TinyMCE will split the `pre` tag. For example:

`<pre>This is inside</pre><pre>a pre tag.</pre>`

> **Note:** When this option is set to `false`, `shift+enter` will insert a `br` tag.
**Type:** `Boolean`

**Default value:** `true`

**Possible values:** `true`, `false`

### Example: using `br_in_pre`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  br_in_pre: false
});
```

## `convert_fonts_to_spans`

> **Important:** This option has been deprecated in TinyMCE 5.10 and may be removed in a future major TinyMCE release.
If you set this option to `true`, TinyMCE will convert all `font` elements to `span` elements and generate `span` elements instead of `font` elements. This option should be used in order to get more W3C compatible code, since font elements are deprecated.

**Type:** `Boolean`

**Default value:** `true`

**Possible values:** `true`, `false`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  convert_fonts_to_spans: false
});
```

## `custom_elements`

This option enables you to specify non-HTML elements for the editor.

This way you can handle non-HTML elements inside an HTML editor. You can prefix the element names with a `~` if you want the element to behave as a `span` element and not a `div` element.

**Type:** `String` or `Object`

### Simple string format

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  extended_valid_elements: 'mycustomblock[id],mycustominline',
  custom_elements: 'mycustomblock,~mycustominline' // Notice the ~ prefix to force a span element for the element
});
```

### Record format

The `custom_elements` option and the `addCustomElements` API support a record structure. The key is the element name, and the value is a specification object with the following properties:

`extends` (string) The element name from which the new element inherits its default properties. Using `extends` also adds the new element as a valid child wherever the extended element is valid. For example, `extends: "div"` makes the custom element block-level and allows it wherever `div` is allowed.

`attributes` (array of strings) List of attribute names or the preset `@global`. Each string is either an attribute name or the preset `@global`, which expands to the schema’s global attributes (see [Attribute preset: `@global`](#attribute-preset-global)). For example: `["@global", "data-type", "data-id"]`.

`children` (array of strings) List of valid child element names or presets. Each string is either an element name or one of the presets `@blocks`, `@phrasing`, or `@flow`. See [HTML Element Sets: `html4`](#html4), [HTML Element Sets: `html5`](#html5), and [HTML Element Sets: `html5-strict`](#html5-strict) for the exact element sets per schema.

`padEmpty` (boolean) Defaults to `false`. When `true`, the element is padded with content (for example, a non-breaking space) when saved so that it always has some content. Use for elements that must not be empty.

`componentUrl` (string) URL of the web component script to load into the editor. Use when the custom element is a web component that requires its script to render.

### Attribute preset: `@global`

The `@global` preset in the `attributes` array expands to the schema’s global attributes. The exact set depends on the schema type:

### HTML Element Sets: `html4`

| Type | Expected |
| --- | --- |
| @blocks | address, blockquote, div, dl, fieldset, form, h1, h2, h3, h4, h5, h6, hr, menu, ol, p, pre, table, ul, center, dir, isindex, noframes |
| @phrasing | a, abbr, b, bdo, br, button, cite, code, del, dfn, em, embed, i, iframe, img, input, ins, kbd, label, map, noscript, object, q, s, samp, script, select, small, span, strong, sub, sup, textarea, u, var, #text, #comment, acronym, applet, basefont, big, font, strike, tt |
| @flow | Same as @blocks + @phrasing |
| @global (attributes) | id, accesskey, class, dir, lang, style, tabindex, title, role, xml:lang |

### HTML Element Sets: `html5`

| Type | Expected |
| --- | --- |
| @blocks | address, blockquote, div, dl, fieldset, form, h1, h2, h3, h4, h5, h6, hr, menu, ol, p, pre, table, ul, article, aside, details, dialog, figure, main, header, footer, hgroup, section, nav, a, ins, del, canvas, map, center, dir, isindex, noframes |
| @phrasing | a, abbr, b, bdo, br, button, cite, code, del, dfn, em, embed, i, iframe, img, input, ins, kbd, label, map, noscript, object, q, s, samp, script, select, small, span, strong, sub, sup, textarea, u, var, #text, #comment, audio, canvas, command, data, datalist, mark, meter, output, picture, progress, time, wbr, video, ruby, bdi, keygen, svg, acronym, applet, basefont, big, font, strike, tt |
| @flow | Same as @blocks + @phrasing |
| @global (attributes) | id, accesskey, class, dir, lang, style, tabindex, title, role, contenteditable, contextmenu, draggable, dropzone, hidden, spellcheck, translate, itemprop, itemscope, itemtype, xml:lang |

### HTML Element Sets: `html5-strict`

| Type | Expected |
| --- | --- |
| @blocks | address, blockquote, div, dl, fieldset, form, h1, h2, h3, h4, h5, h6, hr, menu, ol, p, pre, table, ul, article, aside, details, dialog, figure, main, header, footer, hgroup, section, nav, a, ins, del, canvas, map |
| @phrasing | a, abbr, b, bdo, br, button, cite, code, del, dfn, em, embed, i, iframe, img, input, ins, kbd, label, map, noscript, object, q, s, samp, script, select, small, span, strong, sub, sup, textarea, u, var, #text, #comment, audio, canvas, command, data, datalist, mark, meter, output, picture, progress, time, wbr, video, ruby, bdi, keygen, svg |
| @flow | Same as @blocks + @phrasing |
| @global (attributes) | id, accesskey, class, dir, lang, style, tabindex, title, role, contenteditable, contextmenu, draggable, dropzone, hidden, spellcheck, translate, itemprop, itemscope, itemtype |

### Example using `custom_elements` with presets such as `@blocks`, `@phrasing`, and `@flow`

```js
tinymce.init({
  selector: "textarea",
  // Add custom elements using the custom_elements option
  custom_elements: {
    // Custom element 'foo-bar' extends 'div' with attributes 'attr1' and 'attr2'
    "foo-bar": {
      extends: "div",
      attributes: ["attr1", "attr2"],
    },
    // Custom element 'foo-baz' extends 'span' allowing children '@phrasing' and 'foo-child'
    "foo-baz": {
      extends: "span",
      children: ["@phrasing", "foo-child"],
    },
    // Custom element 'foo-child' has no specific configuration
    "foo-child": {},
  },
  // You can also use the addCustomElements API to add custom elements
  setup: (editor) => {
    editor.on("preinit", () => {
      editor.schema.addCustomElements({
        // Custom element 'hey-bar' extends 'div' with attributes 'attr1' and 'attr2' as well as all global attributes
        "hey-bar": {
          extends: "div",
          attributes: ["@global", "attr1", "attr2"],
        },
        // Custom element 'hey-baz' extends 'span' allowing children 'hey-child' as well as all phrasing content
        "hey-baz": {
          extends: "span",
          children: ["@phrasing", "hey-child"],
        },
        // Custom element 'hey-child' has no specific configuration
        "hey-child": {},
      });
    });
  },
});
```

### Example using `custom_elements` with `padEmpty` and `componentUrl`

```js
tinymce.init({
  selector: "textarea",
  custom_elements: {
    // Custom element that is padded when empty
    "my-empty-padded": {
      extends: "div",
      padEmpty: true,
    },
    // Block-level custom element (behaves like a div) with web component
    "my-custom-block": {
      extends: "div",
      attributes: ["@global", "data-type", "data-id"],
      children: ["@flow"],
      componentUrl: "/path/to/block-component.js"
    },
    // Inline-level custom element (behaves like a span) with web component
    "my-custom-inline": {
      extends: "span",
      attributes: ["@global", "data-value"],
      children: ["@phrasing"],
      componentUrl: "/path/to/inline-component.js"
    }
  }
});
```

## `convert_unsafe_embeds` option

This option controls whether an `<object>` and `<embed>` elements will be converted to more restrictive alternatives, namely `<img>` for image MIME types, `<video>` for video MIME types, `<audio>` for audio MIME types, or `<iframe>` for other or unspecified MIME types.

When converted to `<img>`, `<video>`, or `<audio>`, this prevents the embedded resource from performing potentially malicious actions including scripting, file downloads, browser popups, passing the same-origin policy, among others. Enable the `sandbox_iframes` option in addition to ensure <iframe> conversions are also neutralised.

**Type:** `Boolean`

**Default value:** `true`

**Possible values:** `true`, `false`

### Example: using `convert_unsafe_embeds` option

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your html
  convert_unsafe_embeds: false
});
```

## `doctype`

Set the `doctype` for the editing area.

> **Warning:** Changing the `doctype` can have different effects on different browsers and may introduce quirks. Use this feature only if you know what you are doing. For more information on doctypes, go to [this link](https://www.w3.org/wiki/Doctypes_and_markup_styles).

## `element_format`

This option controls whether elements are output in the HTML or XHTML mode. `html` is the default state for this option. This means that for example `<br />` will be `<br>` by default.

**Type:** `String`

**Default value:** `'html'`

**Possible values:** `'xhtml'`, `'html'`

### Example: using `element_format`

```js
// Output elements in XHTML style
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  element_format: 'xhtml'
});
```

## `encoding`

This option allows you to get XML escaped content out of TinyMCE. By setting this option to `xml`, posted content will be converted to an XML string, escaping characters such as `<`, `>`, `"`, `'` and `&` to `&lt;`, `&gt;`, `&quot;`, `&apos;` and `&amp;`.

This option is disabled by default.

**Type:** `String`

### Example: using `encoding`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  encoding: 'xml'
});
```

## `entities`

This option contains a comma-separated list of entity names that are used instead of characters. Odd items are the character code, and even items are the names of the character code.

The base entities `<`, `>`, `&`, `'`, and `"` will always be entity encoded into their named equivalents. Though, `'` and `"` will only be encoded within attribute values and `<` and `>` will only be encoded within text nodes. This is correct according to the HTML and XML specifications.

*This setting will only encode characters higher than \u007E (126 in unicode).*

**Type:** `String`

**Default value:**

```js
'160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,' +
'167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,' +
'reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,' +
'micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,' +
'frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,' +
'Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,' +
'201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,' +
'Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,' +
'214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,' +
'Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,' +
'227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,' +
'eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,' +
'240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,' +
'ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,' +
'253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,' +
'916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,' +
'923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,' +
'Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,' +
'alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,' +
'theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,' +
'omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,' +
'phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,' +
'bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,' +
'weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,' +
'uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,' +
'8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,' +
'empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,' +
'8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,' +
'8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,' +
'8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,' +
'8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,' +
'perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,' +
'lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,' +
'diams,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,' +
'732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,' +
'lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,' +
'8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,' +
'permil,8249,lsaquo,8250,rsaquo,8364,euro'
```

### Example: using `entities`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  entities: '160,nbsp,162,cent,8364,euro,163,pound'
});
```

## `entity_encoding`

This option controls how entities/characters get processed by TinyMCE. The value can be set as shown in *Encoding types* below. You can also mix named and numeric by setting this to "named+numeric" this way it will produce entity names of the ones found in the configured entities and numeric entities for other entities.

The base entities `<`, `>`, `&`, `'`, and `"` will always be entity encoded into their named equivalents. Though, `'` and `"` will only be encoded within attribute values and `<` and `>` will only be encoded within text nodes. This is correct according to the HTML and XML specs.

### Encoding types

| Name | Summary |
| --- | --- |
| named | Characters will be converted into named entities based on the entities option. For example, a non-breaking space could be encoded as `&nbsp;`. This value is default. |
| numeric | Characters will be converted into numeric entities. For example, a non-breaking space would be encoded as `&#160;`. |
| raw | All characters will be stored in non-entity form except these XML default entities: `&`, `<`, `>`, `'`, and `"`. |

**Type:** `String`

#### Example: using `entity_encoding`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  entity_encoding: 'raw'
});
```

## `extended_valid_elements`

This option is very similar to [`valid_elements`](#valid_elements). The only difference between this option and `valid_elements` is that this one gets added to the existing rule set. This can be very useful if the existing rule set is fine but you want to add some specific elements that also should be valid. The default rule set is controlled by the [`schema`](#schema) option.

When adding a new attribute by specifying an existing element rule (e.g. `img`), the entire rule for that element is over-ridden so be sure to include all valid attributes not just the one you wish to add. See [`valid_elements`](#valid_elements) for default rules.

The below example replaces the current `img` rule (including the global element rules).

**Type:** `String`

### Example: using `extended_valid_elements`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  extended_valid_elements: 'img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name]'
});
```
Also see [valid_elements](#valid_elements) and [invalid_elements](#invalid_elements) for more configuration options.

### Using extended_valid_elements to allow script elements

> **Warning:** Allowing script elements (`<script>`) in TinyMCE exposes users to [cross-site scripting (XSS) attacks](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting).
To allow script elements in the editor, include the following in the TinyMCE configuration:

```
extended_valid_elements: 'script[src|async|defer|type|charset]'
```

### Interactive example

This example shows you how to use the [extended_valid_elements](#extended_valid_elements) option. This option is used to add additional valid elements and attributes.

**Example**

```js
tinymce.init({
  selector: 'textarea#valid-elements',
  plugins: 'code',
  height: 500,
  extended_valid_elements: 'img[class=myclass|!src|border~0|alt|title|width|height|style]',
  invalid_elements: 'strong,b,em,i',
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }'
});
```

## `fix_list_elements`

This option enables you to specify that list elements (`ul`, `ol`) should be converted to valid XHTML. This option is disabled by default since it causes some glitches with a few browsers.

This invalid list:

```html
<ol>
  <li>a</li>
    <ol>
      <li>b</li>
      <li>c</li>
   </ol>
    <li>e</li>
</ol>
```
Gets converted into this valid list:

```html
<ol>
  <li>a
    <ol>
      <li>b</li>
      <li>c</li>
    </ol>
  </li>
  <li>e</li>
</ol>
```
**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

### Example: using `fix_list_elements`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  fix_list_elements: true
});
```

## `forced_root_block`

This option enables you to adjust the default block element used to wrap non block elements and text nodes. For example `<strong>something</strong>` will result in output like: `<p><strong>something</strong></p>`. This option cannot be disabled.

To avoid block elements in content, use the [newline_behavior](../content-behavior-options/#newline_behavior) setting to change what happens when enter is pressed.

> **Warning:** Not using `p` elements as the root block will impair the functionality of the editor.
**Type:** `String`

**Default value:** `'p'`

### Example: using `forced_root_block`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  forced_root_block: 'div'
});
```

## `forced_root_block_attrs`

This option enables you specify attributes for the [forced_root_block](#forced_root_block).

**Type:** `Object`

### Example: using `forced_root_block_attrs`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  forced_root_block_attrs: {
    'class': 'myclass',
    'data-something': 'my data'
  }
});
```

## `indent`

This option, which is on by default, adds a newline character — U+000A, `\n` — between closing and opening block elements when HTML is output using `getContent()` and when HTML is rendered in the TinyMCE [Preview](../preview/) dialog.

Set `indent` to `false` to get HTML output from TinyMCE without having any newline characters added.

**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

### Example: setting `indent` to false

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  indent: false,
});
```

## `invalid_elements`

This option instructs the editor to remove specific elements when TinyMCE executes a cleanup. This option should contain a comma-separated list of element names to exclude from the content.

**Type:** `String`

### Example: using `invalid_elements`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  invalid_elements: 'strong,em'
});
```

> **Caution:** This option does not accept attributes in the list, only elements.

> **Important:** The `invalid_elements` option takes precedence over element rules with exact names in the [`valid_elements`](#valid_elements) and [`extended_valid_elements`](#extended_valid_elements) options. It has no effect on elements that match a wildcard rule, such as `*[*]`, `*[class]`, or `h?`, in either option.
Also see [valid_elements](#valid_elements) and [extended_valid_elements](#extended_valid_elements) for more configuration options.

## `invalid_styles`

This option enables you to restrict the styles that are valid for specific elements. It takes two input formats:

- **String format** - This is a list of global styles to disallow.
- **Object format** - This is a more complex format in which you can specify invalid styles for individual elements.

### Simple global classes

**Type:** `String`, `Object`

#### Example: using `invalid_styles` string

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  invalid_styles: 'color font-size'
});
```

### Element specific classes

**Type:** `String`, `Object`

#### Example: using `invalid_styles` object

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  invalid_styles: {
    '*': 'color font-size', // Global invalid styles
    'a': 'background' // Link specific invalid styles
  }
});
```

## `pad_empty_with_br`

By default, TinyMCE places non-breaking space entities — `&nbsp;` — as placeholders inside empty block elements.

For example, the empty paragraph `<p></p>` will, by default, be serialized to `<p>&nbsp;</p>`.

The `pad_empty_with_br` option enables TinyMCE to change this default placeholder to a break tag: `<br>`.

For example, when this option is set to `true`, an empty paragraph, `<p></p>`, is serialized to `<p><br></p>`.

**Type:** `Boolean`

**Default value:** `false`

**Possible values:** `true`, `false`

### Example: using `pad_empty_with_br`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your html
  pad_empty_with_br: true,
});
```

## `protect`

This configuration option enables you to control what contents should be protected from editing while it gets passed into the editor. This could, for example, be control codes in the HTML. It’s recommended not to use inline control contents since it breaks the WYSIWYG editing concept, but sometimes they can’t be avoided.

The option takes an array of regular expression that it will match the contents against and these will be invisible while editing.

**Type:** `Array`

### Example: using `protect`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  protect: [
    /\<\/?(if|endif)\>/g,  // Protect <if> & </endif>
    /\<xsl\:[^>]+\>/g,  // Protect <xsl:...>
    /<\?php.*?\?>/g  // Protect php code
  ]
});
```

## `remove_trailing_brs`

This option allows you to disable TinyMCE’s default behavior of removing `<br>` tags at the end of block elements.

[Gecko](https://en.wikipedia.org/wiki/Gecko_(software)) and [WebKit](https://en.wikipedia.org/wiki/WebKit) browsers inject these elements to make it possible to place the caret in empty blocks. This logic attempts to remove these elements while also keeping tags that were intentionally placed by the user.

**Type:** `Boolean`

**Default value:** `true`

**Possible values:** `true`, `false`

### Example: using `remove_trailing_brs`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  remove_trailing_brs: false
});
```

## `sandbox_iframes`

This option allows control of whether `<iframe>` elements are [sandboxed](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox) when inserted into the editor. When enabled, all `<iframe>` elements will be given the `sandbox=""` attribute, applying all restrictions.

**Type:** `Boolean`

**Default value:** `true`

**Possible values:** `true`, `false`

### Example: using `sandbox_iframes` option

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your html
  sandbox_iframes: false
});
```

## `sandbox_iframes_exclusions`

This option allows a list of domains to be specified that should be excluded from having the `sandbox=""` attribute applied when the `sandbox_iframes` option is enabled. This option takes an array of strings, each denoting at least the top and second level of a domain to be excluded. By default, this option is set to an array of domains that are provided in embed code by popular websites. To enable [sandboxing](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox) on all iframes, set this option to an empty array `[]`.

> **Note:** When the `sandbox_iframes` option is set to `false`, all domains will be excluded from sandboxing.
**Type:** `Array`

**Default value:**

```js
[
  'youtube.com',
  'youtu.be',
  'vimeo.com',
  'player.vimeo.com',
  'dailymotion.com',
  'embed.music.apple.com',
  'open.spotify.com',
  'giphy.com',
  'dai.ly',
  'codepen.io'
]
```

### Example: using `sandbox_iframes_exclusions` option

```js
tinymce.init({
  selector: "textarea",
  sandbox_iframes: true,
  sandbox_iframes_exclusions: [
    'youtube.com',
    'youtu.be',
    'vimeo.com',
    'player.vimeo.com',
    'dailymotion.com',
    'embed.music.apple.com',
    'open.spotify.com',
    'giphy.com',
    'dai.ly',
    'codepen.io'
  ],
});
```

## `schema`

This option enables you to switch between the HTML4 and HTML5 schema. This controls the valid elements and attributes that can be placed in the HTML. This value can either be the default `html5`, `html4` or `html5-strict`.

The html5 schema is the full HTML5 specification including the older HTML4 elements for compatibility. The html5-strict will only allow the elements that are in the current HTML5 specification excluding things that were removed. The html4 schema includes the full html4 transitional specification.

Also note that all event attributes are excluded by default since it’s a bad practice to use inline script handles like "onclick". You can manually add extra elements and attributes using the [extended_valid_elements](#extended_valid_elements) option.

**Type:** `String`

**Default value:** `'html5'`

**Possible values:** `'html5'`, `'html4'`, `'html5-strict'`

### Example: using `schema`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  schema: 'html5'
});
```

## `valid_children`

This option enables you to control what child elements can exist within specified parent elements.

TinyMCE will remove/split any non HTML5 or HTML transitional contents by default. So for example a `p` can’t be a child of another `p` element. The default value for this option is controlled by the current [schema](#schema).

The syntax for this option is a comma separated list of parents with elements that should be added/removed as valid children for that element. So for example `'+body[style]'` would add style as a valid child of body.

### Control characters

| Name | Summary |
| --- | --- |
| + | Adds children to the list of valid elements for the specified parent. |
| - | Removes children from the list of valid children for the specified parent. |

This example shows you how to add `style` as a valid child of `body` and remove `div` as a valid child. It also forces only `strong`, `a`, and `text` contents to be valid children of `p`.

**Type:** `String`

### Example: using `valid_children`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  valid_children: '+body[style],-body[div],p[strong|a|#text]'
});
```
This is an option you shouldn’t have to fiddle with. The default rule set for this follows the HTML5 specification and some legacy elements from HTML4. You can switch between these defaults by configuring the [`schema`](#schema) option.

## `valid_classes`

This option enables you to restrict the classes that are valid for specific elements. This option takes two formats: one string format that is a simple list of allowed global classes, and a more complex object format where you can specify classes for individual elements.

**Type:** `String`, `Object`

### Example simple global classes

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  valid_classes: 'class1 class2 class3'
});
```

### Example element specific classes

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  valid_classes: {
    '*': 'class1 class2 class3', // Global classes
    'a': 'class4 class5' // Link specific classes
  }
});
```

## `valid_elements`

This option defines which elements will remain in the edited text when the editor saves. You can use this to limit the returned HTML to a subset.

This option contains a comma separated list of element conversion chunks. Each chunk contains information about how one element and its attributes should be treated. The default rule set for this option is a mixture of the full [HTML5](https://html.spec.whatwg.org/) and [HTML4](http://www.w3.org/TR/html40/) specification or the HTML5 or HTML4 specification depending on the configured [schema](#schema).

If you just want to add or change some behavior for a few items, use the [extended_valid_elements](#extended_valid_elements) option

### Control characters

Each element rule uses the following structure. Parts in square brackets are optional, and characters in double quotes are literal.

```text
element rule:    [- or #]name[/alias][attribute list]
attribute list:  [!]"[" attribute rule "|" attribute rule "|" ... "]"
attribute rule:  [! or -]name[=value, ~value, or <value?value]
```
The following table lists each control character and the part of the rule it is used in.

| Character | Used in | Summary |
| --- | --- | --- |
| `@` | Element rule | Rules with this name will be applied to all elements defined after this rule. So `@[attr1\|attr2]` will enable `attr1` and `attr2` for all elements, but `element1,@[attr1\|attr2],element2,element3` will enable `attr1` and `attr2` only for `element2` and `element3`. Only the first `@` rule is used. An `@` rule in `valid_elements` also applies to the elements in [`extended_valid_elements`](#extended_valid_elements), and an `@` rule in `extended_valid_elements` is ignored if `valid_elements` already has one. If only `extended_valid_elements` has an `@` rule, it applies only to the elements defined after it in that option. |
| `,` | Rule list | Separates element rules. Do not add spaces after commas. For example, `'p, strong'` does not allow `<strong>` elements. |
| `/` | Element rule | Separates element synonyms. The first element is the one that is output. For example, `strong/b` converts `<b>` elements to `<strong>` elements. |
| `[` | Element rule | Starts the attribute list for an element rule. |
| `]` | Element rule | Ends the attribute list for an element rule. |
| `\|` | Attribute list | Separates attribute rules. |
| `-` | Element rule (prefix) | Removes the element if it is empty. For example, `-strong` removes `<strong></strong>`. |
| `#` | Element rule (prefix) | Pads the element with `&nbsp;` if it is empty. For example, `#p` converts `<p></p>` to `<p>&nbsp;</p>`. |
| `!` | Element rule (before `[`) | Removes the element tag and keeps its content if the element has no attributes. The `!` must be placed directly after the element name, or after the alias, and before the attribute list. For example, `span![class\|style]` converts `<span>text</span>` to `text` and keeps `<span class="note">text</span>`. |
| `!` | Attribute rule (prefix) | Makes the attribute required. If the element has none of its required attributes, the element tag is removed and its content is kept. For example, `a[!href]` converts `<a title="note">text</a>` to `text`. |
| `-` | Attribute rule (prefix) | Removes an attribute that the element inherits from an `@` rule. For example, `@[id\|title],p,a[-title\|href]` allows `id` and `title` on `p` elements, and `id` and `href` on `a` elements. |
| `=` | Attribute rule | Makes the attribute default to the specified value. For example, `a[href\|target=_blank]` adds `target="_blank"` to links that do not have a `target` attribute. |
| `~` | Attribute rule | Forces the attribute to the specified value. For example, `a[href\|target~_blank]` sets `target="_blank"` on all links. |
| `<` | Attribute rule | Lists the allowed values of an attribute. TinyMCE currently parses this rule but does not enforce it. For example, `a[href\|target<_blank?_self]`. |
| `?` | Attribute rule | Separates attribute verification values. See above. |

Wildcards can be used in element and attribute names: `*` matches zero or more characters, `+` matches one or more, and `?` matches zero or one. For example, `td[col*|row*]` allows `colspan` and `rowspan` on `td` elements. A wildcard matches any character, so `h?` matches `h1` to `h6` and also `hr`.

Both forms of `!` are checked again when the content is saved, after attributes that the rule does not allow, or that are unsafe, have been removed. For example, with `span![class]`, `<span title="note">text</span>` is saved as `text`. With `a[!href]`, `<a href="javascript:alert(1)">text</a>` is saved as `text`.

Attributes that start with `data-` or `aria-` are kept when validation is enabled, even if the attribute rules do not list them.

The default rule set removes the tag of `<span>` elements that have no attributes, pads empty block elements, removes empty inline elements, and converts `<b>` and `<i>` to `<strong>` and `<em>`. When `valid_elements` is set, these defaults do not apply. To keep them, use the `!`, `#`, `-`, and `/` controls, for example `span![class|style]`, `#p`, and `-strong/b`. If no rule allows `span`, the tag of every `<span>` element is removed, including elements that have attributes.

### Variables

| Name | Summary |
| --- | --- |
| `{$uid}` | Results in a unique ID. For example, `'p[id~{$uid}]'`. |

> **Caution:** Setting `valid_elements` to `*[*]` allows all elements and all attributes. This is equivalent to disabling validation: event handler attributes such as `onclick` and `<script>` elements are kept, and the [`invalid_elements`](#invalid_elements) option has no effect. Using `*[*]` is not recommended because of the security risks.
**Type:** `String`

### Example: using `valid_elements`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  valid_elements: 'a[href|target=_blank],strong/b,div[align],br'
});
```
This example string tells TinyMCE to:

- Remove all elements that are not a `a`, `strong`, `div` or `br` element.
- Convert `b` elements to `strong` elements.
- Default `target` to `_blank` and keeps the `href`, `target` and `align` attributes of the relevant elements.

### Duplicate attribute warning

Be careful not to duplicate attributes in the definitions as this may cause TinyMCE to render duplicate attributes in the output. For example, if you have:

```js
//bad code: dir and style listed twice
'blockquote[dir|style|cite|class|dir<ltr?rtl|id|lang|onclick|ondblclick'
 +'|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout'
 +'|onmouseover|onmouseup|style|title]'
```
then if you happen to have a `<blockquote>` element in your code with `style=` or `dir=` attributes, the editor will cause each of those attributes to be duplicated in the output, which will result in invalid XHTML.

## `valid_styles`

To use this option, specify an object containing a mapping of element names to allowed styles. To specify the allowed styles for all elements, use `*` as the element name.

By default, all styles are allowed unless `valid_styles` or `invalid_styles` is configured.

**Type:** `Object`

### Example: using `valid_styles`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  valid_styles: {
    '*': 'border,font-size',
    'div': 'width,height'
  }
});
```
