# Root types

In CKEditor 5, a root is the top-level container element in the document model - every editable area has exactly one. The type of that root element determines what content is allowed in that area. By default, roots use the `$root` model element, which accepts block-level content such as paragraphs, headings, lists, and tables.

You can configure a root to use a different model element via the [`config.root.modelElement`](../../api/module_core_editor_editorconfig-RootConfig.md#member-modelElement) option, and set initial root attributes via [`config.root.modelAttributes`](../../api/module_core_editor_editorconfig-RootConfig.md#member-modelAttributes). CKEditor 5 ships with a second built-in root type, `$inlineRoot`, which restricts the root to inline content only - text and inline formatting, but no block elements. This turns the root into a paragraph-like editing area, suitable for document titles, form labels, meta descriptions, and similar single-line fields. For the technical background behind this feature, see the [paragraph-like editor RFC](https://github.com/ckeditor/ckeditor5/issues/19921).

<a id="standard-root">

## Standard root

The default root type is `$root`. It accepts the full range of block-level content: paragraphs, headings, lists, tables, block images, and any other block elements that the enabled plugins support. This is the standard editing experience for most use cases - articles, documents, comments, and similar rich-text areas.

<a id="configuration">

### Configuration

You do not need to set `modelElement` explicitly to get this behavior. The following two configurations are equivalent:

```js
ClassicEditor
	.create( {
		attachTo: document.querySelector( '#editor' ),
		root: {
			initialData: '<p>Start writing here.</p>'
		},
		licenseKey: '<YOUR_LICENSE_KEY>',
		// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

```js
ClassicEditor
	.create( {
		attachTo: document.querySelector( '#editor' ),
		root: {
			initialData: '<p>Start writing here.</p>',
			modelElement: '$root'
		},
		licenseKey: '<YOUR_LICENSE_KEY>',
		// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

<a id="allowed-content-in-a-standard-root">

### Allowed content in a standard root

A standard root accepts whatever block elements the enabled plugins register: paragraphs, headings, lists, tables, block images, code blocks, and similar. Inline content such as text and formatting must appear inside those block elements - it cannot be placed directly in the root. This reflects the standard document structure enforced by the [schema](../../framework/deep-dive/schema.md#generic-items): root → blocks → inline content.

<a id="inline-root">

## Inline root

A root configured with `$inlineRoot` behaves like a single paragraph: pressing `Enter` has no effect, because inserting a new block is not allowed.

<a id="configuration-2">

### Configuration

To configure any single-root editor type as inline-only, set [`modelElement`](../../api/module_core_editor_editorconfig-RootConfig.md#member-modelElement) to `'$inlineRoot'` in the `root` config:

**NPM**

```js
import { ClassicEditor, Essentials, Bold, Italic } from 'ckeditor5';

ClassicEditor
	.create( {
		attachTo: document.querySelector( '#editor' ),
		root: {
			initialData: 'My document title',
			modelElement: '$inlineRoot'
		},
		licenseKey: '<YOUR_LICENSE_KEY>',
		plugins: [ Essentials, Bold, Italic ],
		toolbar: [ 'bold', 'italic' ]
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

**CDN**

```js
const { ClassicEditor, Essentials, Bold, Italic } = CKEDITOR;

ClassicEditor
	.create( {
		attachTo: document.querySelector( '#editor' ),
		root: {
			initialData: 'My document title',
			modelElement: '$inlineRoot'
		},
		licenseKey: '<YOUR_LICENSE_KEY>',
		plugins: [ Essentials, Bold, Italic ],
		toolbar: [ 'bold', 'italic' ]
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

The `modelElement` option works with all editor types: `ClassicEditor`, `InlineEditor`, `BalloonEditor`, `BalloonBlockEditor`, `DecoupledEditor`, and `MultiRootEditor`.

<a id="allowed-content-in-an-inline-root">

### Allowed content in an inline root

The `$inlineRoot` model element allows the same content as a paragraph: text nodes and inline objects. Block elements are not permitted. Where a standard root follows the root → blocks → inline content structure, an inline root skips the block layer entirely: root → inline content. For a deeper look at how CKEditor 5 schema controls content rules, see the [Schema deep dive](../../framework/deep-dive/schema.md#generic-items) guide.

| Content type                                             | Allowed |
| -------------------------------------------------------- | ------- |
| Plain text                                               | Yes     |
| Inline formatting (bold, italic, underline, and similar) | Yes     |
| Links                                                    | Yes     |
| Mentions                                                 | Yes     |
| Inline images                                            | Yes     |
| Paragraphs and headings                                  | No      |
| Lists                                                    | No      |
| Tables                                                   | No      |
| Block images                                             | No      |

Plugins that only produce block-level output will have no effect inside an `$inlineRoot` root. You can still include such plugins in your editor setup - they will be inactive when the cursor is inside an inline root, and toolbar items for block-only features will be disabled.

<a id="mixed-root-types-in-multi-root-editor">

## Mixed root types in multi-root editor

Mixing root types lets different parts of the same document use different content models. In a multi-root editor, you can configure each root independently. For example, a common pattern is to use an inline root for the title and a standard root for the body:

**NPM**

```js
import { MultiRootEditor, Essentials, Bold, Italic, Paragraph, Heading } from 'ckeditor5';

MultiRootEditor
	.create( {
		roots: {
			title: {
				element: document.querySelector( '#title' ),
				initialData: 'My document title',
				modelElement: '$inlineRoot'
			},
			body: {
				element: document.querySelector( '#body' ),
				initialData: '<p>Main content goes here.</p>'
			}
		},
		licenseKey: '<YOUR_LICENSE_KEY>',
		plugins: [ Essentials, Bold, Italic, Paragraph, Heading ],
		toolbar: [ 'heading', '|', 'bold', 'italic' ]
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

**CDN**

```js
const { MultiRootEditor, Essentials, Bold, Italic, Paragraph, Heading } = CKEDITOR;

MultiRootEditor
	.create( {
		roots: {
			title: {
				element: document.querySelector( '#title' ),
				initialData: 'My document title',
				modelElement: '$inlineRoot'
			},
			body: {
				element: document.querySelector( '#body' ),
				initialData: '<p>Main content goes here.</p>'
			}
		},
		licenseKey: '<YOUR_LICENSE_KEY>',
		plugins: [ Essentials, Bold, Italic, Paragraph, Heading ],
		toolbar: [ 'heading', '|', 'bold', 'italic' ]
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

The `title` root only accepts inline content, while the `body` root accepts the full range of block elements. The toolbar and undo stack are shared between both roots. See [Editor types](editor-types.md#multi-root-editor) for a broader overview of the multi-root editor.

<a id="adding-roots-dynamically">

### Adding roots dynamically

In a multi-root editor, you can add roots at runtime using [`editor.addRoot()`](../../api/module_editor-multi-root_multirooteditor-MultiRootEditor.md#function-addRoot:ROOT_CONFIG). The `modelElement` option sets the root type, the same way as in the static configuration:

```js
editor.on( 'addRoot', ( evt, root ) => {
	const editableElement = editor.createEditable( root );

	document.querySelector( '#editors' ).appendChild( editableElement );
} );

// Add a standard root.
editor.addRoot( 'section', {
	initialData: '<p>Section content.</p>'
} );

// Add an inline root.
editor.addRoot( 'sectionTitle', {
	modelElement: '$inlineRoot',
	initialData: 'Section title'
} );
```

The root type is fixed at creation time and cannot be changed afterward.

<a id="configuring-the-host-element">

## Configuring the host element

The [`root.element`](../../api/module_core_editor_editorconfig-RootConfig.md#member-element) option specifies the DOM element the editor uses as the editable area. For non-classic editors, it also accepts a tag name string or an element definition object - letting you control the element’s tag, CSS classes, attributes, and inline styles directly from the editor configuration.

<a id="choosing-a-semantic-element">

### Choosing a semantic element

By default, the editor creates a `<div>` as the editable area. For non-classic editors, consider passing a semantically appropriate element instead. For example, if the inline root serves as a document title, an `<h1>` element is a better fit:

```js
InlineEditor
	.create( {
		root: {
			element: document.querySelector( 'h1#title' ),
			modelElement: '$inlineRoot'
		},
		licenseKey: '<YOUR_LICENSE_KEY>',
		// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

> **Note**
>
> When using a semantic element such as `<h1>` as the editable area, keep in mind that the `.ck-content` CSS class applied to all editables defines default font and line-height values that may override the element’s native browser styles. If this affects your layout, scope the relevant [CSS variables](content-styles.md#general-content-styling) to that element.

<a id="applying-classes-and-styles">

### Applying classes and styles

Instead of targeting the editable element with a global CSS selector, you can apply CSS classes and inline styles directly from the editor configuration. Pass an element definition object to `root.element` with `name`, `classes`, `attributes`, and `styles` fields. The example below adds a custom class and sets a minimum and maximum height on the editable area:

```js
InlineEditor
	.create( {
		root: {
			element: {
				name: 'h1',
				classes: [ 'my-editor' ],
				styles: {
					'min-height': '300px',
					'max-height': '500px' // Adds a scrollbar when content overflows.
				}
			},
			initialData: 'My document title',
			modelElement: '$inlineRoot'
		},
		licenseKey: '<YOUR_LICENSE_KEY>',
		// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

The `classes` array and `styles` object are applied to the editable element. This is useful for controlling dimensions, scoping CSS rules, or integrating with a class-based styling system. For broader CSS customization options, see the [Editor styles](editor-styles.md) and [Content styles](content-styles.md) guides.

<a id="styling-inline-roots">

## Styling inline roots

When you mount an inline root on a non-block HTML element such as a `<span>`, the browser may render the editable area with unexpected line breaks or sizing. This happens because block-filler mechanisms used by the editor can interact poorly with inline host elements.

The editor adds the `ck-editor__editable_inline-root` CSS class to the editable element whenever the root uses `$inlineRoot`. You can target this class to apply styles specific to inline roots:

```css
.ck-editor__editable_inline-root {
	display: inline-block;
	max-width: fit-content;
	min-width: 50px;
}
```

This ensures the editing area does not collapse or stretch beyond its content. The `min-width` keeps the editable wide enough to show the placeholder when the root is empty. Mounting on a block element like a `<div>` does not require any extra CSS.

> **Note**
>
> When using a `<span>` as the host element, also set `display: inline-block` on the `<span>` itself, since block-level children are not valid inside an inline element.

---

Full index of the CKEditor 5 documentation: [llms.txt](../../../llms.txt)
