# Link

The link feature lets you insert hyperlinks into your content and provides a UI to create and edit them. Thanks to the [autolink](#autolink-feature) plugin, typed or pasted URLs and email addresses are automatically converted into working links.

<a id="demo">

## Demo

Use the link toolbar button or press `Ctrl`/`Cmd`+`K` to create a new link. Clicking a link opens a contextual toolbar. The toolbar lets you edit existing links or unlink them with a click.

<!-- 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="typing-around-links">

## Typing around links

CKEditor 5 allows typing at the inner and outer link boundaries to make editing simpler for the users.

**To type inside a link**, move the caret to its (start or end) boundary. As long as the link remains highlighted (by default: blue), typing and applying formatting happens within its boundaries:

**To type before or after a link**, move the caret to its boundary, then press the Arrow key (`←` or `→`) away from the link once. The link stops from being highlighted, and whatever text you type or formatting apply will not be inside the link:

<a id="installation">

## Installation

After [installing the editor](../getting-started/installation/cloud/quick-start.md), add the feature to your plugin list and toolbar configuration:

**NPM**

```js
import { ClassicEditor, AutoLink, Link } from 'ckeditor5';

ClassicEditor
	.create( {
		licenseKey: '<YOUR_LICENSE_KEY>', // Or 'GPL'.
		plugins: [ Link, AutoLink, /* ... */ ],
		toolbar: [ 'link', /* ... */ ],
		link: {
			// Configuration.
		}
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

**CDN**

```js
const { ClassicEditor, AutoLink, Link } = CKEDITOR;

ClassicEditor
	.create( {
		licenseKey: '<YOUR_LICENSE_KEY>',
		plugins: [ Link, AutoLink, /* ... */ ],
		toolbar: [ 'link', /* ... */ ],
		link: {
			// Configuration.
		}
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

<a id="link-toolbar-configuration">

## Link toolbar configuration

The link UI contains a contextual toolbar that appears when a link is selected. You can configure what items appear in this toolbar using the [`config.link.toolbar`](../api/module_link_linkconfig-LinkConfig.md#member-toolbar) option.

The following toolbar items are available:

* `'linkPreview'` – Shows a preview of the link URL that you can click to open the link in a new tab.
* `'editLink'` – Opens a form to edit the link URL and options.
* `'linkProperties'` – Opens a panel to configure link properties (manual decorators). Only available when at least one manual decorator is defined.
* `'unlink'` – Removes the link.

By default, the link toolbar is configured as follows:

```js
ClassicEditor
	.create( {
		link: {
			toolbar: [ 'linkPreview', '|', 'editLink', 'linkProperties', 'unlink' ]
		}
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

<a id="custom-toolbar-items">

### Custom toolbar items

You can extend the link toolbar with custom items by registering them in the [component factory](../api/module_ui_componentfactory-ComponentFactory.md) and adding them to the toolbar configuration.

Here is an example of registering a custom component:

```js
class MyCustomPlugin extends Plugin {
	init() {
		const editor = this.editor;

		editor.ui.componentFactory.add( 'myCustomLinkInfo', locale => {
			const button = new ButtonView( locale );
			const linkCommand = editor.commands.get( 'link' );

			button.bind( 'isEnabled' ).to( linkCommand, 'value', href => !!href );
			button.bind( 'label' ).to( linkCommand, 'value' );

			button.on( 'execute', () => {
				// Add your custom component logic here
			} );

			return button;
		} );
	}
}
```

Once registered, the component can be used in the toolbar configuration:

```js
ClassicEditor
	.create( {
		plugins: [ MyCustomPlugin, /* ... */ ],
		link: {
			toolbar: [ 'myCustomLinkInfo', '|', 'editLink', 'unlink' ]
		}
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

> **Note**
>
> The `linkProperties` item is only shown when manual decorators are configured through [`config.link.decorators`](../api/module_link_linkconfig-LinkConfig.md#member-decorators). See the [custom link attributes](#custom-link-attributes-decorators) section for more details.

<a id="custom-link-attributes-decorators">

## Custom link attributes (decorators)

By default, all links created in the editor have the `href="..."` attribute in the [editor data](../getting-started/setup/getting-and-setting-data.md#getting-the-editor-data-with-getdata). If you want your links to have additional link attributes, [link decorators](../api/module_link_linkconfig-LinkConfig.md#member-decorators) provide an easy way to configure and manage them.

There are two types of link decorators you can use:

* [**Automatic**](#adding-attributes-to-links-based-on-predefined-rules-automatic-decorators) – They match links against predefined rules and manage their attributes based on the results.
* [**Manual**](#adding-attributes-to-links-using-the-ui-manual-decorators) – They allow users to control link attributes individually using the editor UI.

> **Note**
>
> Link decorators are turned off by default and it takes a proper [configuration](#configuration) to enable them in your rich-text editor.

<a id="demo-2">

### Demo

In the editor below, all **external** links get the `target="_blank"` and `rel="noopener noreferrer"` attributes ([automatic decorator](#adding-attributes-to-links-based-on-predefined-rules-automatic-decorators)). Click a link and edit it to see that you can control the `download` attribute of specific links using the switch button in the editing balloon ([manual decorator](#adding-attributes-to-links-using-the-ui-manual-decorators)).

<!-- 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. -->

The following code runs this editor. Learn more about the [configuration](#configuration) of the feature.

```js
ClassicEditor
	.create( {
		// ... Other configuration options ...
		link: {
			// Automatically add target="_blank" and rel="noopener noreferrer"
			// to all external links.
			addTargetToExternalLinks: true,

			// Let the users control the "download" attribute of each link.
			decorators: [
				{
					mode: 'manual',
					label: 'Downloadable',
					attributes: {
						download: 'download'
					}
				}
			]
		}
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

<a id="configuration">

### Configuration

You can configure decorators through definitions provided in the [`config.link.decorators`](../api/module_link_linkconfig-LinkConfig.md#member-decorators) configuration option.

Each decorator definition must have a unique name. For [manual decorators](#adding-attributes-to-links-using-the-ui-manual-decorators), the name also represents the decorator in the [document model](../framework/architecture/editing-engine.md#text-attributes).

> **Warning**
>
> Link decorators work independently of one another and no conflict resolution mechanism exists. For example, configuring the `target` attribute using both an automatic and a manual decorator at the same time could end up with quirky results. The same applies if you define more manual or automatic decorators for the same attribute.

<a id="adding-target-and-rel-attributes-to-external-links">

#### Adding `target` and `rel` attributes to external links

A common use case for (automatic) link decorators is adding the `target="_blank"` and `rel="noopener noreferrer"` attributes to all external links in the document. A dedicated [`config.link.addTargetToExternalLinks`](../api/module_link_linkconfig-LinkConfig.md#member-addTargetToExternalLinks) configuration exists for that purpose. When you set this option to `true`, all links starting with `http://`, `https://`, or `//` are “decorated” with `target` and `rel` attributes.

```js
ClassicEditor
	.create( {
		// ... Other configuration options ...
		link: {
			addTargetToExternalLinks: true
		}
		// More of the editor's configuration.
			// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

Internally, this configuration corresponds to an [automatic decorator](#adding-attributes-to-links-based-on-predefined-rules-automatic-decorators) with the following [definition](../api/module_link_linkconfig-LinkDecoratorAutomaticDefinition.md):

```js
ClassicEditor
	.create( {
		// ... Other configuration options ...
		link: {
			decorators: {
				addTargetToExternalLinks: {
					mode: 'automatic',
					callback: url => /^(https?:)?\/\//.test( url ),
					attributes: {
						target: '_blank',
						rel: 'noopener noreferrer'
					}
				}
			}
		}
		// More of the editor's configuration.
			// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

If you want to leave the decision whether a link should open in a new tab to the users, do not use the `config.link.addTargetToExternalLinks` configuration. Define a new [manual decorator](#adding-attributes-to-links-using-the-ui-manual-decorators) with the following definition instead:

```js
ClassicEditor
	.create( {
		// ... Other configuration options ...
		link: {
			decorators: {
				openInNewTab: {
					mode: 'manual',
					label: 'Open in a new tab',
					attributes: {
						target: '_blank',
						rel: 'noopener noreferrer'
					}
				}
			}
		}
		// More of the editor's configuration.
			// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

<a id="adding-default-link-protocol-to-external-links">

#### Adding default link protocol to external links

A default link protocol can be useful when the user forgets to type the full URL address to an external source or website. Sometimes copying the text, like for example `ckeditor.com`, and converting it to a link may cause some issues. As a result, the created link will direct you to `yourdomain.com/ckeditor.com` because of the missing protocol. This makes the link relative to the site where it appears.

After you enable the [`config.link.defaultProtocol`](../api/module_link_linkconfig-LinkConfig.md#member-defaultProtocol) configuration option, the link feature will be able to handle this issue for you. By default, it does not fix the passed link value, but when you set [`config.link.defaultProtocol`](../api/module_link_linkconfig-LinkConfig.md#member-defaultProtocol) to, for example, `http://`, the plugin will add the given protocol to every link that may need it (like `ckeditor.com`, `example.com`, etc. where `[protocol://]example.com` is missing).

See a basic configuration example:

```js
ClassicEditor
	.create( {
		// ... Other configuration options ...
		link: {
			defaultProtocol: 'http://'
		}
		// More of the editor's configuration.
			// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

> **Note**
>
> With the [`config.link.defaultProtocol`](../api/module_link_linkconfig-LinkConfig.md#member-defaultProtocol) option enabled, you are still able to link things locally using `#` or `/`. The protocol will not be added to these links.
>
> When enabled, this feature also provides the **email address autodetection** feature. When you submit `hello@example.com` in your content, the plugin will automatically change it to `mailto:hello@example.com`.

<a id="adding-custom-protocols-in-links">

#### Adding custom protocols in links

By default, a minimal set of protocols is allowed to be used in the links. Any URL with an unrecognized protocol will be changed to ‘#’. You can overwrite the list of protocols by using [`config.link.allowedProtocols`](../api/module_link_linkconfig-LinkConfig.md#member-allowedProtocols).

See a configuration example:

```js
ClassicEditor
	.create( {
		// ... Other configuration options ...
		link: {
			// You can use `s?` suffix like below to allow both
			// `http` and `https` protocols at the same time.
			allowedProtocols: [ 'https?', 'tel', 'sms', 'sftp', 'smb', 'slack' ]
		}
		// More of the editor's configuration.
		// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

> **Warning**
>
> Please remember that you customize this list at your own risk – adding unsafe protocols like `javascript` can lead to serious security vulnerabilities!

<a id="adding-attributes-to-links-based-on-predefined-rules-automatic-decorators">

#### Adding attributes to links based on predefined rules (automatic decorators)

Automatic link decorators match all links in the editor content against a [function](../api/module_link_linkconfig-LinkDecoratorAutomaticDefinition.md) which decides whether the link should receive some set of attributes, considering the URL (`href`) of the link. These decorators work silently and the editor applies them during the [data downcast](../framework/architecture/editing-engine.md#conversion).

For instance, to create an automatic decorator that adds the `download="file.pdf"` attribute to all links ending with the `".pdf"` extension, you should add the following [definition](../api/module_link_linkconfig-LinkDecoratorAutomaticDefinition.md) to [`config.link.decorators`](../api/module_link_linkconfig-LinkConfig.md#member-decorators):

```js
ClassicEditor
	.create( {
		// ... Other configuration options ...
		link: {
			decorators: {
				detectDownloadable: {
					mode: 'automatic',
					callback: url => url.endsWith( '.pdf' ),
					attributes: {
						download: 'file.pdf'
					}
				}
			}
		}
		// More of the editor's configuration.
		// ...
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

> **Note**
>
> If you want add the `target` and `rel` attributes to all external links in your content, we prepared a [dedicated configuration](#adding-target-and-rel-attributes-to-external-links) for that purpose. Thanks to this, you do not have to define the automatic decorator by yourself.

<a id="adding-classes-and-styles-to-links">

#### Adding classes and styles to links

In addition to adding custom HTML attributes, link decorators can also apply CSS classes and inline styles to a link. It works for both **automatic** decorators (based on rules) and **manual** decorators (toggled in the UI). You must provide classes and styles through the dedicated `classes` and `styles` properties in the decorator configuration.

Manual decorators add a toggle to the link UI, allowing the user to enable or disable additional link features. The decorator properties are applied to the link element whenever the toggle is enabled.

```js
ClassicEditor
	.create( {
		link: {
			decorators: {
				highlighted: {
					mode: 'manual',
					label: 'Highlighted link',
					defaultValue: false,
					classes: 'link-highlighted',
					styles: {
						background: 'yellow',
						'font-weight': 'bold'
					}
				}
			}
		}
	} );
```

When you enable the “Highlighted link” toggle, the editor output adds the class and styles to the link element.

<a id="adding-attributes-to-links-using-the-ui-manual-decorators">

#### Adding attributes to links using the UI (manual decorators)

Manual link decorators are represented in the link editing balloon as switch buttons. The users can use them to control the presence of attributes of a particular link (check out the [demo](#demo) to learn more). Each manual decorator [definition](../api/module_link_linkconfig-LinkDecoratorManualDefinition.md) has a human-readable label displayed next to the switch button in the link editing balloon. Make sure it is compact and precise for the convenience of the users.

To configure a “Downloadable” switch button in the link editing balloon that adds the `download="file"` attribute to the link when turned on, add the following definition to [`config.link.decorators`](../api/module_link_linkconfig-LinkConfig.md#member-decorators):

```js
ClassicEditor
	.create( {
		// ... Other configuration options ...
		link: {
			decorators: {
				toggleDownloadable: {
					mode: 'manual',
					label: 'Downloadable',
					attributes: {
						download: 'file'
					}
				},
				openInNewTab: {
					mode: 'manual',
					label: 'Open in a new tab',
					defaultValue: true,			// This option will be selected by default.
					attributes: {
						target: '_blank',
						rel: 'noopener noreferrer'
					}
				}
			}
		}
	} )
	.then( /* ... */ )
	.catch( /* ... */ );
```

<a id="deprecated-syntax">

#### Deprecated syntax

Older versions of CKEditor 5 allowed classes and styles inside the `attributes` field:

```js
// ❌ Deprecated – do not use:
attributes: {
	class: 'my-class',
	style: 'color: red'
}
```

> **Warning**
>
> This syntax remains compatible for backward purposes but is deprecated and triggers a console warning. Use the `classes` and `styles` properties instead.

<a id="autolink-feature">

## Autolink feature

The [`AutoLink`](../api/module_link_autolink-AutoLink.md) feature will automatically turn URLs or email addresses into working links.

To use the autolink function, press `Space`, `Enter`, or `Shift`+`Enter` after a link.

> **Note**
>
> You can always revert autolinking by the undo feature (`Ctrl`/`Cmd`+`Z`) or the backspace (`⌫`) button.

<!-- 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. -->

<a id="link-providers">

## Link providers

<a id="demo-3">

### Demo

The link feature integrates with [bookmarks](bookmarks.md), providing a smooth linking experience. Link providers allow adding predefined lists of links (similar to bookmarks). You can register any links you would like to use frequently in your content in the Link plugin using a custom method. These links will be available in the link UI form for easy access.

<!-- 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. -->

<a id="configuration-2">

### Configuration

To define a list of links available in the link UI, you can use the `getListItems()` function in the link provider. Opening the group in the link UI calls the function every time. The function should return an array of objects, each representing a link.

The `getItem()` function can resolve the link. Opening the link preview or navigating to the link from the editing view calls the function. It should return an object with the `href`, `icon`, `label`, and `tooltip` parameters. The properties are assigned to the link preview. It is useful when only part of the list items are shown in the list view (for example, in pagination), and the user interacts with a link that is not visible in the list view but is available in the editing.

```js
class SocialLinksPlugin extends Plugin {
	static get requires() {
		return [ Link ];
	}

	async init() {
		const linkUI = this.editor.plugins.get( LinkUI );

		linkUI.registerLinksListProvider( {
			label: 'Social links',
			getListItems: () => [
				{
					id: 'facebook',
					href: 'https://facebook.com',
					label: 'Facebook',
					icon: linkIcon
				},
				{
					id: 'twitter',
					href: 'https://twitter.com',
					label: 'Twitter',
					icon: linkIcon
				}
			],

			// Optionally: You can customize your link preview
			// by custom implementation of link getter.
			getItem: href => {
				return {
					href,
					icon: linkIcon,
					label: 'My custom label in link preview',
					tooltip: 'My custom tooltip in link preview'
				};
			}
		} );
	}
}
```

<a id="common-api">

## Common API

The [`Link`](../api/module_link_link-Link.md) plugin registers the UI button component (`'link'`) and the following commands:

* The `'link'` command implemented by [`LinkCommand`](../api/module_link_linkcommand-LinkCommand.md).
* The `'unlink'` command implemented by [`UnlinkCommand`](../api/module_link_unlinkcommand-UnlinkCommand.md).

You can execute the commands using the [`editor.execute()`](../api/module_core_editor_editor-Editor.md#function-execute) method:

```js
// Applies the link to the selected content.
// When the selection is collapsed, it creates new text wrapped in a link.
editor.execute( 'link', 'http://example.com' );

// If there are decorators configured, the command can set their state.
editor.execute( 'link', 'http://example.com', { linkIsExternal: true } );

// Removes the link from the selection (and all decorators if present).
editor.execute( 'unlink' );
```

The package provides a plugin for [linking images](../api/module_link_linkimage-LinkImage.md). See the [Linking images](images/images-linking.md) guide in the [Images section](images/images-overview.md).

Links are represented in the [model](../api/module_engine_model_model-Model.md) using the `linkHref` attribute. [Manual link decorators](#adding-attributes-to-links-using-the-ui-manual-decorators) are represented in the model using text attributes corresponding to their names, as configured in [`config.link.decorators`](../api/module_link_linkconfig-LinkConfig.md#member-decorators).

> **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-link>.

---

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