diff --git a/packages/block-editor/src/components/link-control/settings.js b/packages/block-editor/src/components/link-control/settings.js
index e63ef926358fe..bbec936d1641e 100644
--- a/packages/block-editor/src/components/link-control/settings.js
+++ b/packages/block-editor/src/components/link-control/settings.js
@@ -18,17 +18,26 @@ const LinkControlSettings = ( { value, onChange = noop, settings } ) => {
 		} );
 	};
 
-	const theSettings = settings.map( ( setting ) => (
-		<CheckboxControl
-			__nextHasNoMarginBottom
-			className="block-editor-link-control__setting"
-			key={ setting.id }
-			label={ setting.title }
-			onChange={ handleSettingChange( setting ) }
-			checked={ value ? !! value[ setting.id ] : false }
-			help={ setting?.help }
-		/>
-	) );
+	const theSettings = settings.map( ( setting ) =>
+		setting.render ? (
+			<div
+				key={ setting.id }
+				className="block-editor-link-control__setting"
+			>
+				{ setting.render( setting, value, onChange ) }
+			</div>
+		) : (
+			<CheckboxControl
+				__nextHasNoMarginBottom
+				className="block-editor-link-control__setting"
+				key={ setting.id }
+				label={ setting.title }
+				onChange={ handleSettingChange( setting ) }
+				checked={ value ? !! value[ setting.id ] : false }
+				help={ setting?.help }
+			/>
+		)
+	);
 
 	return (
 		<fieldset className="block-editor-link-control__settings">
diff --git a/packages/block-editor/src/components/link-control/style.scss b/packages/block-editor/src/components/link-control/style.scss
index 16493e1a5aa7f..a8afa9e2ffc12 100644
--- a/packages/block-editor/src/components/link-control/style.scss
+++ b/packages/block-editor/src/components/link-control/style.scss
@@ -346,11 +346,15 @@ $block-editor-link-control-number-of-actions: 1;
 .block-editor-link-control__setting {
 	margin-bottom: 0;
 	flex: 1;
-	padding: $grid-unit-10 0 $grid-unit-10 $grid-unit-30;
+	padding: $grid-unit-10 $grid-unit-30;
 
-	.components-base-control__field {
-		display: flex; // don't allow label to wrap under checkbox.
+	.components-base-control:not(.components-input-control) {
+		.components-base-control__field {
+			display: flex; // don't allow label to wrap under checkbox.
+		}
+	}
 
+	.components-base-control__field {
 		.components-checkbox-control__label {
 			color: $gray-900;
 		}
diff --git a/packages/format-library/src/link/index.js b/packages/format-library/src/link/index.js
index 508ed4655a669..7225514b21978 100644
--- a/packages/format-library/src/link/index.js
+++ b/packages/format-library/src/link/index.js
@@ -227,6 +227,7 @@ export const link = {
 		_id: 'id',
 		target: 'target',
 		rel: 'rel',
+		class: 'class',
 	},
 	__unstablePasteRule( value, { html, plainText } ) {
 		const pastedText = ( html || plainText )
diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js
index 964e9a4271dda..b9f3832746309 100644
--- a/packages/format-library/src/link/inline.js
+++ b/packages/format-library/src/link/inline.js
@@ -1,10 +1,18 @@
 /**
  * WordPress dependencies
  */
-import { useMemo, createInterpolateElement } from '@wordpress/element';
+import {
+	useState,
+	useMemo,
+	createInterpolateElement,
+} from '@wordpress/element';
 import { __, sprintf } from '@wordpress/i18n';
 import { speak } from '@wordpress/a11y';
-import { Popover } from '@wordpress/components';
+import {
+	Popover,
+	__experimentalInputControl as InputControl,
+	CheckboxControl,
+} from '@wordpress/components';
 import { prependHTTP } from '@wordpress/url';
 import {
 	create,
@@ -30,12 +38,71 @@ import { useDispatch, useSelect } from '@wordpress/data';
 import { createLinkFormat, isValidHref, getFormatBoundary } from './utils';
 import { link as settings } from './index';
 
+const TogglableSettingComponent = ( { setting, value, onChange } ) => {
+	const hasValue = value ? value?.cssClasses?.length > 0 : false;
+	const [ inputVisible, setInputVisible ] = useState( hasValue );
+
+	const handleSettingChange = ( newValue ) => {
+		onChange( {
+			...value,
+			[ setting.id ]: newValue,
+		} );
+	};
+
+	const handleCheckboxChange = () => {
+		if ( inputVisible ) {
+			if ( hasValue ) {
+				// Reset the value.
+				handleSettingChange( '' );
+			}
+			setInputVisible( false );
+		} else {
+			setInputVisible( true );
+		}
+	};
+
+	return (
+		<div className="block-editor-link-control__toggleable-setting">
+			<CheckboxControl
+				__nextHasNoMarginBottom
+				label={ setting.title }
+				onChange={ handleCheckboxChange }
+				checked={ inputVisible || hasValue }
+				help={ setting?.help }
+			/>
+			{ inputVisible && (
+				<InputControl
+					label={ setting.title }
+					value={ value?.cssClasses }
+					onChange={ handleSettingChange }
+					help={ __( 'Separate multiple classes with spaces.' ) }
+					__unstableInputWidth="100%"
+					__next40pxDefaultSize
+				/>
+			) }
+		</div>
+	);
+};
+
 const LINK_SETTINGS = [
 	...LinkControl.DEFAULT_LINK_SETTINGS,
 	{
 		id: 'nofollow',
 		title: __( 'Mark as nofollow' ),
 	},
+	{
+		id: 'cssClasses',
+		title: __( 'Additional CSS class(es)' ),
+		render: ( setting, value, onChange ) => {
+			return (
+				<TogglableSettingComponent
+					setting={ setting }
+					value={ value }
+					onChange={ onChange }
+				/>
+			);
+		},
+	},
 ];
 
 function InlineLinkUI( {
@@ -78,8 +145,10 @@ function InlineLinkUI( {
 			opensInNewTab: activeAttributes.target === '_blank',
 			nofollow: activeAttributes.rel?.includes( 'nofollow' ),
 			title: richTextText,
+			cssClasses: activeAttributes.class,
 		} ),
 		[
+			activeAttributes.class,
 			activeAttributes.id,
 			activeAttributes.rel,
 			activeAttributes.target,
@@ -116,6 +185,7 @@ function InlineLinkUI( {
 					: undefined,
 			opensInNewWindow: nextValue.opensInNewTab,
 			nofollow: nextValue.nofollow,
+			cssClasses: nextValue.cssClasses,
 		} );
 
 		const newText = nextValue.title || newUrl;
diff --git a/packages/format-library/src/link/style.scss b/packages/format-library/src/link/style.scss
index 05eb576fe26e2..32c24b75eb453 100644
--- a/packages/format-library/src/link/style.scss
+++ b/packages/format-library/src/link/style.scss
@@ -17,3 +17,9 @@
 		color: $alert-red;
 	}
 }
+
+.block-editor-link-control__toggleable-setting {
+	display: flex;
+	flex-direction: column;
+	gap: $grid-unit-20 0;
+}
diff --git a/packages/format-library/src/link/utils.js b/packages/format-library/src/link/utils.js
index 314c8118713a4..4f64950efd457 100644
--- a/packages/format-library/src/link/utils.js
+++ b/packages/format-library/src/link/utils.js
@@ -86,6 +86,7 @@ export function isValidHref( href ) {
  * @param {string}  options.id               The ID of the link.
  * @param {boolean} options.opensInNewWindow Whether this link will open in a new window.
  * @param {boolean} options.nofollow         Whether this link is marked as no follow relationship.
+ * @param {string}  options.cssClasses       The CSS classes to apply to the link.
  * @return {Object} The final format object.
  */
 export function createLinkFormat( {
@@ -94,6 +95,7 @@ export function createLinkFormat( {
 	id,
 	opensInNewWindow,
 	nofollow,
+	cssClasses,
 } ) {
 	const format = {
 		type: 'core/link',
@@ -122,6 +124,12 @@ export function createLinkFormat( {
 			: 'nofollow';
 	}
 
+	const trimmedCssClasses = cssClasses?.trim();
+
+	if ( trimmedCssClasses?.length ) {
+		format.attributes.class = trimmedCssClasses;
+	}
+
 	return format;
 }