# Media embed styles

The media embed styles feature lets you apply a style (for example, an alignment) to a media embed such as a YouTube or Vimeo video, a Spotify player, and so on. It is implemented by the [`MediaEmbedStyle`](../../api/module_media-embed_mediaembedstyle-MediaEmbedStyle.md) plugin.

Out of the box the plugin ships five alignment styles. You can pick a subset of the built-ins, override their labels or icons, or register completely new styles through [`config.mediaEmbed.styles`](../../api/module_media-embed_mediaembedconfig-MediaEmbedConfig.md#member-styles).

<a id="installation">

## Installation

The [`MediaEmbedStyle`](../../api/module_media-embed_mediaembedstyle-MediaEmbedStyle.md) plugin is not loaded by default. Add it explicitly alongside [`MediaEmbed`](../../api/module_media-embed_mediaembed-MediaEmbed.md) to enable the feature:

**NPM**

```js
import { ClassicEditor, MediaEmbed, MediaEmbedToolbar, MediaEmbedStyle } from 'ckeditor5';

ClassicEditor
	.create( {
		attachTo: document.querySelector( '#editor' ),
		licenseKey: '<YOUR_LICENSE_KEY>', // Or 'GPL'.
		plugins: [ MediaEmbed, MediaEmbedToolbar, MediaEmbedStyle, /* ... */ ],
		toolbar: [ 'mediaEmbed', /* ... */ ]
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

**CDN**

```js
const { ClassicEditor, MediaEmbed, MediaEmbedToolbar, MediaEmbedStyle } = CKEDITOR;

ClassicEditor
	.create( {
		attachTo: document.querySelector( '#editor' ),
		licenseKey: '<YOUR_LICENSE_KEY>',
		plugins: [ MediaEmbed, MediaEmbedToolbar, MediaEmbedStyle, /* ... */ ],
		toolbar: [ 'mediaEmbed', /* ... */ ]
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

Similarly, [`MediaEmbed`](../../api/module_media-embed_mediaembed-MediaEmbed.md) doesn’t load [`MediaEmbedToolbar`](../../api/module_media-embed_mediaembedtoolbar-MediaEmbedToolbar.md) by default. The toolbar contains style buttons for media embed features. Add `MediaEmbedToolbar` to your `plugins` list, otherwise the entries you put in `config.mediaEmbed.toolbar` never reach the media widget toolbar.

<a id="built-in-styles">

## Built-in styles

The plugin provides the following five style options out of the box. Each option registers a toolbar button under the name `mediaEmbed:<style-name>` (used to place it in `config.mediaEmbed.toolbar`) and, for non-default styles, applies a CSS class to the media `<figure>` element. The default `alignCenter` option emits no class.

**Block alignments** – the media takes a full line, with surrounding text appearing above and below.

* **Left aligned** – button `mediaEmbed:alignBlockLeft`, class `media-style-block-align-left`.
* **Centered** – button `mediaEmbed:alignCenter`; default, no class.
* **Right aligned** – button `mediaEmbed:alignBlockRight`, class `media-style-block-align-right`.

**Wrap-text alignments** – the media floats to one side and surrounding text wraps around it.

* **Left aligned** – button `mediaEmbed:alignLeft`, class `media-style-align-left`.
* **Right aligned** – button `mediaEmbed:alignRight`, class `media-style-align-right`.

> **Note**
>
> The actual styling of the media embeds is the job of the integrator. CKEditor 5 comes with some default styles, but they will only be applied to the media inside the editor. The integrator needs to style them appropriately on the target pages.
>
> You can find the source of the default styles applied by the editor here: [`ckeditor5-media-embed/theme/index-content.css`](https://github.com/ckeditor/ckeditor5/blob/master/packages/ckeditor5-media-embed/theme/index-content.css).
>
> Read more about [styling the content of the editor](../../getting-started/setup/css.md).

The demo below shows the five built-in alignment styles, wired through the two compact split-button dropdowns and combined with the [media embed resize feature](media-embed-resize.md). Select a figure and try the **Wrap text** and **Break text** dropdowns in its contextual toolbar – the action button reflects whichever alignment is currently applied.

<!-- AI-AGENT-NOTE: An interactive demo is embedded here but is not represented in this Markdown file. If you need to see it in action, open this page in a browser (e.g. via a browser-automation MCP like Chrome DevTools or Playwright), or let the user know a live demo is available on this page. -->

This demo presents a limited set of features. Visit the [feature-rich editor example](../../examples/builds-custom/full-featured-editor.md) to see more in action.

<a id="configuring-the-styles">

## Configuring the styles

You can customize the set of available styles through [`config.mediaEmbed.styles`](../../api/module_media-embed_mediaembedconfig-MediaEmbedConfig.md#member-styles). The configuration accepts an `options` array whose entries can be:

* a **string** referencing a built-in style by name (`'alignLeft'`, `'alignBlockLeft'`, `'alignCenter'`, `'alignBlockRight'`, `'alignRight'`),
* an **object** whose `name` matches a built-in (its fields are shallow-merged on top of the built-in),
* an **object** with a new `name` (a fully custom style). See [`MediaStyleOptionDefinition`](../../api/module_media-embed_mediaembedconfig-MediaStyleOptionDefinition.md) for the required and optional fields.

When `config.mediaEmbed.styles` is not provided, all five built-in styles are available. This is the default behavior.

> **Warning**
>
> When a configured style option misses a required field (`name`, `title`, `icon`, or `className` for non-default styles), or references an unknown built-in name, the entry is dropped from the resolved options and a console warning is emitted under the `media-style-configuration-definition-invalid` error code. The other valid entries continue to work as configured.

<a id="picking-a-subset-of-built-in-styles">

### Picking a subset of built-in styles

Pass only the styles you want to expose. Filtered-out styles disappear from the toolbar and cannot be applied through the `'mediaStyle'` command.

```js
mediaEmbed: {
	styles: {
		options: [ 'alignBlockLeft', 'alignCenter', 'alignBlockRight' ]
	}
}
```

In the example above the wrap-text floats (`alignLeft`, `alignRight`) are dropped. The `mediaEmbed:wrapText` dropdown auto-skips because both of its items were filtered out, and only the three block alignments remain.

<a id="overriding-a-built-in-style">

### Overriding a built-in style

To customize a built-in style, pass an object whose `name` matches the built-in plus the fields you want to change. Fields you set replace the built-in’s defaults. Fields you omit are inherited.

```js
mediaEmbed: {
	styles: {
		options: [
			'alignLeft',
			{ name: 'alignCenter', title: 'Center' },
			'alignRight'
		]
	}
}
```

<a id="adding-a-custom-style">

### Adding a custom style

To add a custom style, supply an object with a fresh `name`, a `title`, an `icon`, and a `className`. You own the CSS for the resulting class. The plugin only writes the class to the figure when the style is applied.

```js
import sideMediaIcon from 'path/to/side-media.svg';

ClassicEditor
	.create( {
		// ... Other configuration options ...
		mediaEmbed: {
			toolbar: [ 'mediaEmbed:alignCenter', 'mediaEmbed:side' ],
			styles: {
				options: [
					'alignCenter',
					{
						name: 'side',
						title: 'Side media',
						icon: sideMediaIcon,
						className: 'media-style-side'
					}
				]
			}
		}
	} );
```

> **Note**
>
> The `icon` field accepts either a full SVG XML string (as shown above) or one of the short aliases shipped with the plugin: `'inlineLeft'`, `'left'`, `'center'`, `'right'`, `'inlineRight'`.

```css
/* Your CSS for the custom style. */
.ck-content .media.media-style-side {
	float: right;
	margin: 0 0 1em 1.5em;
	clear: none;
	box-shadow: 0 4px 16px rgba( 0, 0, 0, 0.2 );
}
```

The same mechanism supports purely semantical styles. There is no requirement that a custom style be alignment-flavored.

To group several custom styles under a single split button in the toolbar, see [Custom split-button dropdowns](#toolbar-configuration) below.

<a id="custom-default-style">

### Custom default style

To mark a style as the default, set `isDefault: true`. Default styles do not need a `className` because the default state is encoded on the model as the absence of the `mediaStyle` attribute, so no class is written to the view. Applying a default style clears any other style that was previously set.

```js
import naturalIcon from 'path/to/natural.svg';

mediaEmbed: {
	styles: {
		options: [
			'alignBlockLeft',
			{
				name: 'natural',
				title: 'Natural position',
				icon: naturalIcon,
				isDefault: true
			},
			'alignBlockRight'
		]
	}
}
```

> **Warning**
>
> Only one style should be marked as the default. If multiple are marked, the first one in the resolved options wins. If none is marked, the command has no default. In that case, `command.value` is `false` whenever the selected media has no `mediaStyle` attribute.

<a id="demo">

### Demo

The demo below replaces the built-in alignments with three custom semantic styles – a Featured frame and two side asides grouped in a custom split-button dropdown. Select a figure to open the contextual toolbar.

<!-- AI-AGENT-NOTE: An interactive demo is embedded here but is not represented in this Markdown file. If you need to see it in action, open this page in a browser (e.g. via a browser-automation MCP like Chrome DevTools or Playwright), or let the user know a live demo is available on this page. -->

This demo presents a limited set of features. Visit the [feature-rich editor example](../../examples/builds-custom/full-featured-editor.md) to see more in action.

<a id="toolbar-configuration">

## Toolbar configuration

Each entry in [`config.mediaEmbed.toolbar`](../../api/module_media-embed_mediaembedconfig-MediaEmbedConfig.md#member-toolbar) is either a built-in component name (string) or an inline split-button dropdown definition (object). You can mix them freely.

**Built-in dropdowns**: `mediaEmbed:wrapText` groups the wrap-text alignments and `mediaEmbed:breakText` groups the block alignments. Each dropdown’s action button reflects whichever option from its group is currently applied to the selected media, falling back to the dropdown’s default (`alignLeft` for wrap, `alignCenter` for break) when none is applied. A dropdown is skipped automatically when fewer than two of its items survive your style configuration.

```js
mediaEmbed: {
	toolbar: [ 'mediaEmbed:wrapText', 'mediaEmbed:breakText' ]
}
```

**Flat buttons**: every style is also exposed as an individual button named `mediaEmbed:<style-name>`.

```js
mediaEmbed: {
	toolbar: [
		'mediaEmbed:alignLeft', 'mediaEmbed:alignBlockLeft',
		'mediaEmbed:alignCenter',
		'mediaEmbed:alignBlockRight', 'mediaEmbed:alignRight'
	]
}
```

**Custom split-button dropdowns**: declare your own grouping inline, alongside built-in entries. The definition follows the [`MediaStyleDropdownDefinition`](../../api/module_media-embed_mediaembedconfig-MediaStyleDropdownDefinition.md) shape – `name`, `title`, `items`, `defaultItem` – and all names use the full `mediaEmbed:` prefix.

```js
mediaEmbed: {
	toolbar: [
		'mediaEmbed:alignCenter',
		{
			name: 'mediaEmbed:myAlignments',
			title: 'Alignment',
			items: [ 'mediaEmbed:alignBlockLeft', 'mediaEmbed:alignBlockRight' ],
			defaultItem: 'mediaEmbed:alignBlockLeft'
		}
	]
}
```

Custom dropdowns inherit the same item-filtering and skip behavior as the built-in dropdowns:

* Items referencing styles that are not in the resolved `config.mediaEmbed.styles.options` list are filtered out at registration time. For custom dropdowns this also emits a console warning under `media-style-configuration-definition-invalid` so you know the config was not fully honored. Built-in dropdowns auto-skip silently.
* A dropdown that ends up with fewer than two items is skipped entirely.
* If the configured `defaultItem` was filtered out, the first surviving item becomes the new default.

A dropdown definition is also dropped (with the same warning) when its `name` lacks the `mediaEmbed:` prefix, `items` is empty or contains non-prefixed entries, `defaultItem` is not one of `items`, or `title` is empty.

<a id="interaction-with-resizing">

## Interaction with resizing

> **Note**
>
> If you use the built-in alignment styles, you should combine them with the optional [media embed resize feature](media-embed-resize.md) as the two features were designed to be used together: resizing controls the width, alignment controls the position.
>
> Without the resize feature, embeds span the full width of the editor by default and the alignment classes have no visible effect, because the figure already occupies the full row. Alignment starts producing a visible effect once the figure is narrower than its container (via the resize feature, your own CSS, or `style` preserved by other means).
>
> Custom non-alignment styles (for example, a drop shadow or border treatment) do not depend on width and work regardless of whether resizing is enabled.

The HTML representation of an aligned and [resized](media-embed-resize.md) media embed looks like this:

```html
<figure class="media media_resized media-style-align-left" style="width:50%;">...</figure>
```

<a id="common-api">

## Common API

The [`MediaEmbedStyle`](../../api/module_media-embed_mediaembedstyle-MediaEmbedStyle.md) plugin registers:

* A button for each style option, for example `'mediaEmbed:alignLeft'` and `'mediaEmbed:alignCenter'` (to use in the media embed contextual toolbar).

* Two built-in split-button dropdowns: `'mediaEmbed:wrapText'` and `'mediaEmbed:breakText'`. Each is skipped automatically when fewer than two of its items survive your style configuration.

* Any custom split-button dropdowns declared inline in [`config.mediaEmbed.toolbar`](../../api/module_media-embed_mediaembedconfig-MediaEmbedConfig.md#member-toolbar).

* The [`'mediaStyle'` command](../../api/module_media-embed_mediaembedstyle_mediaembedstylecommand-MediaEmbedStyleCommand.md). It accepts a value matching one of the resolved [configured options](../../api/module_media-embed_mediaembedconfig-MediaEmbedConfig.md#member-styles):

  ```js
  // Float the selected media to the left so text wraps around it.
  editor.execute( 'mediaStyle', { value: 'alignLeft' } );

  // Clear the style to return to the default state.
  editor.execute( 'mediaStyle', { value: null } );
  ```

  Values outside the resolved options are silently rejected. Passing the effective default name (or `null`) always clears the attribute.

> **Note**
>
> We recommend using the official [CKEditor 5 inspector](../../framework/development-tools/inspector.md) for development and debugging. It will give you tons of useful information about the state of the editor such as internal data structures, selection, commands, and many more.

<a id="contribute">

## Contribute

The source code of the feature is available on GitHub at <https://github.com/ckeditor/ckeditor5/tree/master/packages/ckeditor5-media-embed>.

---

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